Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Codacy CI #8

Merged
merged 1 commit into from
Jan 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ _Put an `x` in the boxes that apply_
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation Update (if none of the other choices apply)
- [ ] CI/CD or unit tests improvements
- [ ] Documentation Update
- [ ] CI/CD or unit tests improvements (if none of the other choices apply)

## Further comments

Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,10 @@ jobs:
if: github.event_name == 'pull_request'
with:
recreate: true
path: code-coverage-results.md
path: code-coverage-results.md

- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@v1.3.0
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: coverage/**/coverage.cobertura.xml
7 changes: 6 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,9 @@ If you have a suggestion that would make this better, please fork the repo and c
```sh
dotnet run ./src/Proxarr.Api/Proxarr.Api.csproj
```
<p align="right"><a href="#readme-top"><img src="images/back-to-top.png" alt="back to top" width="35" /></a></p>

<p align="right">
<a href="#readme-top">
<img src="images/back-to-top.png" alt="back to top" width="35" />
</a>
</p>
24 changes: 14 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,22 @@ It uses TMDB to find out which streaming services are available in the selected

* Acquire TMDB API KEY
[How](https://dev.to/codexive_zech/streamlining-your-contribution-how-to-get-your-tmdb-api-key-for-ldbflix-contribution-52gf#:~:text=How%20to%20Obtain%20a%20TMDB%20API%20Key)
* Obtain SONARR/RADARR API KEY<br/>
<img src="images/arr_api_key.png" width="230">
* Obtain SONARR/RADARR API KEY
<br/><img src="images/arr_api_key.png" width="230">

### Installation with Docker compose

1. Prepare your [config.yml][config-yml] to fit your setup
2. On your Radarr/Sonarr instances we have to do some changes
- tag all indexers by the TAG_NAME defined in your [config.yml][config-yml] (`q` by default)<br/>
<img src="images/tagging-indexers.png" width="250" alt="tag indexers" />
- tag all indexers by the TAG_NAME defined in your [config.yml][config-yml] (`q` by default)
<br/><img src="images/tagging-indexers.png" width="250" alt="tag indexers" />
- specify Application URL: is essential because it is used by Proxarr to determine to which instance should return the response<br/>
<img src="images/application_url.png" width="250" alt="Application Url config"/>
- establish a Webhook connection between Sonarr/Radarr and Proxarr<br/>
<img src="images/webhook_config.png" width="250" alt="Application Url config"/><br/>
_Note_ : Webhook URL is `http://<Proxarr_Instance>/api/qualifier
3. Add the following to your docker-compose.yml (to be adapted according to your stack)<br/>
[docker-compose.yml](docker-compose.yml) is an another full example of how to integrate Proxarr with Sonarr and Radarr.
- establish a Webhook connection between Sonarr/Radarr and Proxarr
<br/><img src="images/webhook_config.png" width="250" alt="Application Url config"/>
<br/>_Note_ : Webhook URL is `http://<Proxarr_Instance>/api/qualifier
3. Add the following to your docker-compose.yml (to be adapted according to your stack)
<br/>[docker-compose.yml](docker-compose.yml) is an another full example of how to integrate Proxarr with Sonarr and Radarr.
```yaml
proxarr:
image: synker/proxarr:latest
Expand Down Expand Up @@ -117,7 +117,11 @@ It uses TMDB to find out which streaming services are available in the selected
docker run -itd --rm -e LOG_LEVEL=Debug -p 8880:8880 -v ${PWD}/config:/app/config --name proxarr synker/proxarr:latest
```

<p align="right"><a href="#readme-top"><img src="images/back-to-top.png" alt="back to top" width="35" /></a></p>
<p align="right">
<a href="#readme-top">
<img src="images/back-to-top.png" alt="back to top" width="35" />
</a>
</p>

### Watching providers configuration

Expand Down
13 changes: 6 additions & 7 deletions src/Proxarr.Api.Tests/RadarrServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
_loggerMock = new Mock<ILogger<RadarrService>>();
_tmdbClientMock = new Mock<ITmdbProxy>();
_appConfigMock = new Mock<IOptions<AppConfiguration>>();
_radarrClientMock = new Mock<RadarrClient>(null);

Check warning on line 31 in src/Proxarr.Api.Tests/RadarrServiceTests.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

var appConfig = new AppConfiguration
{
Expand All @@ -45,7 +45,7 @@
[Fact]
public async Task Ctor_ShouldThrowArgNullEx_WhenAppConfigurationNull()
{
Action act = () => new RadarrService(null, null, null, null);

Check warning on line 48 in src/Proxarr.Api.Tests/RadarrServiceTests.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Check warning on line 48 in src/Proxarr.Api.Tests/RadarrServiceTests.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.
act.Should().Throw<ArgumentNullException>().WithParameterName("appConfiguration");
}

Expand All @@ -61,7 +61,7 @@
};
var cancellationToken = new CancellationToken();

_tmdbClientMock.Setup(x => x.GetMovieAsync(123, MovieMethods.WatchProviders, cancellationToken))
_tmdbClientMock.Setup(x => x.GetMovieAsync(123, cancellationToken, MovieMethods.WatchProviders))
.ReturnsAsync(new TMDbLib.Objects.Movies.Movie { WatchProviders = new SingleResultContainer<Dictionary<string, WatchProviders>> { Results = [] } });

_radarrClientMock.Setup(x => x.MovieGET2Async(1, cancellationToken))
Expand All @@ -86,7 +86,7 @@
};
var cancellationToken = new CancellationToken();

_tmdbClientMock.Setup(x => x.GetMovieAsync(123, MovieMethods.WatchProviders, cancellationToken))
_tmdbClientMock.Setup(x => x.GetMovieAsync(123, cancellationToken, MovieMethods.WatchProviders))
.ReturnsAsync((TMDbLib.Objects.Movies.Movie)null);

_radarrClientMock.Setup(x => x.MovieGET2Async(1, cancellationToken))
Expand Down Expand Up @@ -121,7 +121,7 @@

var seriesResource = new MovieResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetMovieAsync(123, MovieMethods.WatchProviders, cancellationToken))
_tmdbClientMock.Setup(x => x.GetMovieAsync(123, cancellationToken, MovieMethods.WatchProviders))
.ReturnsAsync(new TMDbLib.Objects.Movies.Movie { WatchProviders = watchProviders });

_radarrClientMock.Setup(x => x.MovieGET2Async(1, cancellationToken))
Expand Down Expand Up @@ -163,7 +163,7 @@

var movieResource = new MovieResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetMovieAsync(123, MovieMethods.WatchProviders, cancellationToken))
_tmdbClientMock.Setup(x => x.GetMovieAsync(123, cancellationToken, MovieMethods.WatchProviders))
.ReturnsAsync(new TMDbLib.Objects.Movies.Movie { WatchProviders = watchProviders });

_radarrClientMock.Setup(x => x.MovieGET2Async(1, cancellationToken))
Expand Down Expand Up @@ -210,7 +210,7 @@

var movieResource = new MovieResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetMovieAsync(123, MovieMethods.WatchProviders, cancellationToken))
_tmdbClientMock.Setup(x => x.GetMovieAsync(123, cancellationToken, MovieMethods.WatchProviders))
.ReturnsAsync(new TMDbLib.Objects.Movies.Movie { WatchProviders = watchProviders });

_radarrClientMock.Setup(x => x.MovieGET2Async(1, cancellationToken))
Expand Down Expand Up @@ -246,10 +246,9 @@
};
var cancellationToken = new CancellationToken();


var movieResource = new MovieResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetMovieAsync(123, MovieMethods.WatchProviders, cancellationToken))
_tmdbClientMock.Setup(x => x.GetMovieAsync(123, cancellationToken, MovieMethods.WatchProviders))
.ReturnsAsync(new TMDbLib.Objects.Movies.Movie());

_radarrClientMock.Setup(x => x.MovieGET2Async(1, cancellationToken))
Expand Down
14 changes: 7 additions & 7 deletions src/Proxarr.Api.Tests/SonarrServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public async Task Qualify_ShouldReturnNotFound_WhenSeriesNotFoundIntoSonarr()
};
var cancellationToken = new CancellationToken();

_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, TvShowMethods.WatchProviders, null, null, cancellationToken))
_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, cancellationToken, TvShowMethods.WatchProviders))
.ReturnsAsync(new TvShow { WatchProviders = new SingleResultContainer<Dictionary<string, WatchProviders>> { Results = [] } });

_sonarrClientMock.Setup(x => x.SeriesGETAsync(1, false, cancellationToken))
Expand All @@ -85,7 +85,7 @@ public async Task Qualify_ShouldReturnNotFound_WhenSeriesNotFoundIntoTMDB()
};
var cancellationToken = new CancellationToken();

_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, TvShowMethods.WatchProviders, null, null, cancellationToken))
_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, cancellationToken, TvShowMethods.WatchProviders))
.ReturnsAsync((TvShow)null);

_sonarrClientMock.Setup(x => x.SeriesGETAsync(1, false, cancellationToken))
Expand Down Expand Up @@ -120,7 +120,7 @@ public async Task Qualify_ShouldUpdateTags_WhenSeriesFound()

var seriesResource = new SeriesResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, TvShowMethods.WatchProviders, null, null, cancellationToken))
_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, cancellationToken, TvShowMethods.WatchProviders))
.ReturnsAsync(new TvShow { WatchProviders = watchProviders });

_sonarrClientMock.Setup(x => x.SeriesGETAsync(1, false, cancellationToken))
Expand Down Expand Up @@ -162,7 +162,7 @@ public async Task Qualify_Should_NotBeTagged_When_MatchedWatchProvider()

var seriesResource = new SeriesResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, TvShowMethods.WatchProviders, null, null, cancellationToken))
_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, cancellationToken, TvShowMethods.WatchProviders))
.ReturnsAsync(new TvShow { WatchProviders = watchProviders });

_sonarrClientMock.Setup(x => x.SeriesGETAsync(1, false, cancellationToken))
Expand Down Expand Up @@ -208,7 +208,7 @@ public async Task Qualify_Should_BeTagged_When_MatchedWatchProvider()

var seriesResource = new SeriesResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, TvShowMethods.WatchProviders, null, null, cancellationToken))
_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, cancellationToken, TvShowMethods.WatchProviders))
.ReturnsAsync(new TvShow { WatchProviders = watchProviders });

_sonarrClientMock.Setup(x => x.SeriesGETAsync(1, false, cancellationToken))
Expand Down Expand Up @@ -244,8 +244,8 @@ public async Task Qualify_Should_BeTagged_When_NoWatchProvider()

var seriesResource = new SeriesResource { Id = 1, Title = "Test Series", Tags = [] };

_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, TvShowMethods.WatchProviders, null, null, cancellationToken))
.ReturnsAsync(new TvShow ());
_tmdbClientMock.Setup(x => x.GetTvShowAsync(123, cancellationToken, TvShowMethods.WatchProviders))
.ReturnsAsync(new TvShow());

_sonarrClientMock.Setup(x => x.SeriesGETAsync(1, false, cancellationToken))
.ReturnsAsync(seriesResource);
Expand Down
2 changes: 1 addition & 1 deletion src/Proxarr.Api/Configuration/ClientConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Proxarr.Api.Configuration
[ExcludeFromCodeCoverage]
public sealed class ClientConfiguration
{
public const string SECTION_NAME = $"{AppConfiguration.SECTION_NAME}:Clients";
public static string SECTION_NAME { get; } = $"{AppConfiguration.SECTION_NAME}:Clients";

/// <summary>
/// Must be Sonarr or Radarr
Expand Down
7 changes: 6 additions & 1 deletion src/Proxarr.Api/Core/CronJobService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,15 @@ protected virtual async Task ScheduleJob(CancellationToken cancellationToken)
while (!cancellationToken.IsCancellationRequested)
{
var next = _expression.GetNextOccurrence(DateTimeOffset.Now, timeZoneInfo);
if (!next.HasValue) continue;

if (!next.HasValue)
{
continue;
}

logger.LogInformation("{JobName}: scheduled next run at {NextRun}", GetType().Name, next.ToString());
var delay = next.Value - DateTimeOffset.Now;

if (delay.TotalMilliseconds <= 0) // prevent non-positive values from being passed into Timer
{
logger.LogInformation("{LoggerName}: scheduled next run is in the past. Moving to next.", GetType().Name);
Expand Down
6 changes: 5 additions & 1 deletion src/Proxarr.Api/Core/Http/BasicAuthenticationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ namespace Proxarr.Api.Core.Http
[ExcludeFromCodeCoverage]
public class BasicAuthenticationDefaults
{
public const string AuthenticationScheme = "Basic";
protected BasicAuthenticationDefaults()
{
}

public static string AuthenticationScheme { get; } = "Basic";
}

[ExcludeFromCodeCoverage]
Expand Down
22 changes: 17 additions & 5 deletions src/Proxarr.Api/Core/TmdbProxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ namespace Proxarr.Api.Core
{
public interface ITmdbProxy
{
Task<Movie> GetMovieAsync(int movieId, MovieMethods extraMethods = MovieMethods.Undefined, CancellationToken cancellationToken = default);
Task<TvShow> GetTvShowAsync(int id, TvShowMethods extraMethods = TvShowMethods.Undefined, string language = null, string includeImageLanguage = null, CancellationToken cancellationToken = default);
Task<Movie> GetMovieAsync(int movieId, MovieMethods extraMethods = MovieMethods.Undefined);
Task<Movie> GetMovieAsync(int movieId, CancellationToken cancellationToken, MovieMethods extraMethods = MovieMethods.Undefined);
Task<TvShow> GetTvShowAsync(int id, TvShowMethods extraMethods = TvShowMethods.Undefined);
Task<TvShow> GetTvShowAsync(int id, CancellationToken cancellationToken, TvShowMethods extraMethods = TvShowMethods.Undefined);
}

[ExcludeFromCodeCoverage]
Expand All @@ -22,12 +24,22 @@ public TmdbProxy(TMDbClient tMDbClient)
_tMDbClient = tMDbClient;
}

public Task<TvShow> GetTvShowAsync(int id, TvShowMethods extraMethods = TvShowMethods.Undefined, string language = null, string includeImageLanguage = null, CancellationToken cancellationToken = default)
public Task<TvShow> GetTvShowAsync(int id, TvShowMethods extraMethods = TvShowMethods.Undefined)
{
return _tMDbClient.GetTvShowAsync(id, extraMethods, language, includeImageLanguage, cancellationToken);
return _tMDbClient.GetTvShowAsync(id, extraMethods, null, null, CancellationToken.None);
}

public Task<Movie> GetMovieAsync(int movieId, MovieMethods extraMethods = MovieMethods.Undefined, CancellationToken cancellationToken = default)
public Task<TvShow> GetTvShowAsync(int id, CancellationToken cancellationToken, TvShowMethods extraMethods = TvShowMethods.Undefined)
{
return _tMDbClient.GetTvShowAsync(id, extraMethods, null, null, cancellationToken);
}

public Task<Movie> GetMovieAsync(int movieId, MovieMethods extraMethods = MovieMethods.Undefined)
{
return _tMDbClient.GetMovieAsync(movieId, extraMethods, CancellationToken.None);
}

public Task<Movie> GetMovieAsync(int movieId, CancellationToken cancellationToken, MovieMethods extraMethods = MovieMethods.Undefined)
{
return _tMDbClient.GetMovieAsync(movieId, extraMethods, cancellationToken);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Proxarr.Api/Services/RadarrService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task<string> Qualify(MovieAdded movieAdded, CancellationToken cance
_logger.LogInformation("Qualifying movie {Title}", movieAdded.Movie.Title);

var tmdbItem = await _tMDbClient
.GetMovieAsync(movieAdded.Movie.TmdbId, TMDbLib.Objects.Movies.MovieMethods.WatchProviders, cancellationToken)
.GetMovieAsync(movieAdded.Movie.TmdbId, cancellationToken, TMDbLib.Objects.Movies.MovieMethods.WatchProviders)
.ConfigureAwait(false);

if (tmdbItem != null)
Expand Down Expand Up @@ -135,7 +135,7 @@ private async Task<bool> AddTag(MovieResource movieRadarr,
{
_logger.LogInformation("Adding tag {Tag} for {Title}", tag.Label, movieRadarr.Title);
movieRadarr.Tags.Add(tag.Id);
updated = true;
return true;
}

return updated;
Expand Down
4 changes: 2 additions & 2 deletions src/Proxarr.Api/Services/SonarrService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public async Task<string> Qualify(TvAdded tvAdded, CancellationToken cancellatio
_logger.LogInformation("Qualifying tv {Title}", tvAdded.Series.Title);

var tmdbItem = await _tMDbClient
.GetTvShowAsync(tvAdded.Series.TmdbId, TMDbLib.Objects.TvShows.TvShowMethods.WatchProviders, cancellationToken: cancellationToken)
.GetTvShowAsync(tvAdded.Series.TmdbId, cancellationToken, TMDbLib.Objects.TvShows.TvShowMethods.WatchProviders)
.ConfigureAwait(false);

if (tmdbItem != null)
Expand Down Expand Up @@ -135,7 +135,7 @@ private async Task<bool> AddTag(SeriesResource seriesSonarr,
{
_logger.LogInformation("Adding tag {Tag} for {Title}", tag.Label, seriesSonarr.Title);
seriesSonarr.Tags.Add(tag.Id);
updated = true;
return true;
}

return updated;
Expand Down
Loading