Skip to content

Commit

Permalink
Remove custom api key (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
MBR-0001 authored Apr 5, 2024
1 parent 1ae4798 commit c3e0179
Show file tree
Hide file tree
Showing 9 changed files with 39 additions and 82 deletions.
9 changes: 6 additions & 3 deletions Jellyfin.Plugin.OpenSubtitles/API/OpenSubtitlesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.OpenSubtitles.OpenSubtitlesHandler;
using Jellyfin.Plugin.OpenSubtitles.OpenSubtitlesHandler.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -38,8 +39,10 @@ public class OpenSubtitlesController : ControllerBase
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
public async Task<ActionResult> ValidateLoginInfo([FromBody] LoginInfoInput body)
{
var key = !string.IsNullOrWhiteSpace(body.CustomApiKey) ? body.CustomApiKey : OpenSubtitlesPlugin.ApiKey;
var response = await OpenSubtitlesHandler.OpenSubtitles.LogInAsync(body.Username, body.Password, key, CancellationToken.None).ConfigureAwait(false);
var response = await OpenSubtitlesApi.LogInAsync(
body.Username,
body.Password,
CancellationToken.None).ConfigureAwait(false);

if (!response.Ok)
{
Expand All @@ -59,7 +62,7 @@ public async Task<ActionResult> ValidateLoginInfo([FromBody] LoginInfoInput body

if (response.Data is not null)
{
await OpenSubtitlesHandler.OpenSubtitles.LogOutAsync(response.Data, key, CancellationToken.None).ConfigureAwait(false);
await OpenSubtitlesApi.LogOutAsync(response.Data, CancellationToken.None).ConfigureAwait(false);
}

return Ok(new { Downloads = response.Data?.User?.AllowedDownloads ?? 0 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ public class PluginConfiguration : BasePluginConfiguration
/// </summary>
public string Password { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the custom API Key.
/// </summary>
public string CustomApiKey { get; set; } = string.Empty;

/// <summary>
/// Gets or sets a value indicating whether the credentials are invalid.
/// </summary>
Expand Down
35 changes: 11 additions & 24 deletions Jellyfin.Plugin.OpenSubtitles/OpenSubtitleDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,6 @@ public OpenSubtitleDownloader(ILogger<OpenSubtitleDownloader> logger, IHttpClien
/// </summary>
public static OpenSubtitleDownloader? Instance { get; private set; }

/// <summary>
/// Gets the API key that will be used for requests.
/// </summary>
public string ApiKey
{
get
{
return !string.IsNullOrWhiteSpace(_configuration?.CustomApiKey) ? _configuration.CustomApiKey : OpenSubtitlesPlugin.ApiKey;
}
}

/// <inheritdoc />
public string Name
=> "Open Subtitles";
Expand Down Expand Up @@ -173,7 +162,7 @@ public async Task<IEnumerable<RemoteSubtitleInfo>> Search(SubtitleSearchRequest

_logger.LogDebug("Search query: {Query}", options);

var searchResponse = await OpenSubtitlesHandler.OpenSubtitles.SearchSubtitlesAsync(options, ApiKey, cancellationToken).ConfigureAwait(false);
var searchResponse = await OpenSubtitlesApi.SearchSubtitlesAsync(options, cancellationToken).ConfigureAwait(false);

if (!searchResponse.Ok)
{
Expand All @@ -183,7 +172,7 @@ public async Task<IEnumerable<RemoteSubtitleInfo>> Search(SubtitleSearchRequest

bool MediaFilter(ResponseData x) =>
x.Attributes?.FeatureDetails?.FeatureType == (request.ContentType == VideoContentType.Episode ? "Episode" : "Movie")
&& x.Attributes?.Files?.Count > 0 && x.Attributes.Files[0].FileId != null
&& x.Attributes?.Files?.Count > 0 && x.Attributes.Files[0].FileId is not null
&& (request.ContentType == VideoContentType.Episode
? x.Attributes.FeatureDetails.SeasonNumber == request.ParentIndexNumber
&& x.Attributes.FeatureDetails.EpisodeNumber == request.IndexNumber
Expand Down Expand Up @@ -261,8 +250,8 @@ private async Task<SubtitleResponse> GetSubtitlesInternal(string id, Cancellatio
var language = idParts[1];
var fileId = int.Parse(idParts[2], CultureInfo.InvariantCulture);

var info = await OpenSubtitlesHandler.OpenSubtitles
.GetSubtitleLinkAsync(fileId, format, _login, ApiKey, cancellationToken)
var info = await OpenSubtitlesApi
.GetSubtitleLinkAsync(fileId, format, _login, cancellationToken)
.ConfigureAwait(false);

if (info.Data?.ResetTime is not null)
Expand Down Expand Up @@ -321,7 +310,7 @@ private async Task<SubtitleResponse> GetSubtitlesInternal(string id, Cancellatio
throw new HttpRequestException(msg);
}

var res = await OpenSubtitlesHandler.OpenSubtitles.DownloadSubtitleAsync(info.Data.Link, cancellationToken).ConfigureAwait(false);
var res = await OpenSubtitlesApi.DownloadSubtitleAsync(info.Data.Link, cancellationToken).ConfigureAwait(false);

if (res.Code != HttpStatusCode.OK || string.IsNullOrWhiteSpace(res.Body))
{
Expand Down Expand Up @@ -355,20 +344,18 @@ private async Task Login(CancellationToken cancellationToken)
return;
}

var loginResponse = await OpenSubtitlesHandler.OpenSubtitles.LogInAsync(
var loginResponse = await OpenSubtitlesApi.LogInAsync(
_configuration.Username,
_configuration.Password,
ApiKey,
cancellationToken).ConfigureAwait(false);

if (!loginResponse.Ok)
{
// 400 = Using email, 401 = invalid credentials, 403 = invalid api key
// 400 = Using email, 401 = invalid credentials
if ((loginResponse.Code == HttpStatusCode.BadRequest && _configuration.Username.Contains('@', StringComparison.OrdinalIgnoreCase))
|| loginResponse.Code == HttpStatusCode.Unauthorized
|| (loginResponse.Code == HttpStatusCode.Forbidden && ApiKey == _configuration.CustomApiKey))
|| loginResponse.Code == HttpStatusCode.Unauthorized)
{
_logger.LogError("Login failed due to invalid credentials/API key, invalidating them ({Code} - {Body})", loginResponse.Code, loginResponse.Body);
_logger.LogError("Login failed due to invalid credentials, invalidating them ({Code} - {Body})", loginResponse.Code, loginResponse.Body);
_configuration.CredentialsInvalid = true;
OpenSubtitlesPlugin.Instance!.SaveConfiguration(_configuration);
}
Expand All @@ -394,7 +381,7 @@ private async Task UpdateUserInfo(CancellationToken cancellationToken)
return;
}

var infoResponse = await OpenSubtitlesHandler.OpenSubtitles.GetUserInfo(_login, ApiKey, cancellationToken).ConfigureAwait(false);
var infoResponse = await OpenSubtitlesApi.GetUserInfo(_login, cancellationToken).ConfigureAwait(false);
if (infoResponse.Ok)
{
_login.User = infoResponse.Data?.Data;
Expand All @@ -415,7 +402,7 @@ private async Task<string> GetLanguage(string language, CancellationToken cancel

if (_languages is null || _languages.Count == 0)
{
var res = await OpenSubtitlesHandler.OpenSubtitles.GetLanguageList(ApiKey, cancellationToken).ConfigureAwait(false);
var res = await OpenSubtitlesApi.GetLanguageList(cancellationToken).ConfigureAwait(false);

if (!res.Ok || res.Data?.Data is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,4 @@ public class LoginInfoInput
/// </summary>
[Required]
public string Password { get; set; } = null!;

/// <summary>
/// Gets or sets the custom api key.
/// </summary>
public string CustomApiKey { get; set; } = null!;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@ namespace Jellyfin.Plugin.OpenSubtitles.OpenSubtitlesHandler;
/// <summary>
/// The open subtitles helper class.
/// </summary>
public static class OpenSubtitles
public static class OpenSubtitlesApi
{
/// <summary>
/// Login.
/// </summary>
/// <param name="username">The username.</param>
/// <param name="password">The password.</param>
/// <param name="apiKey">The api key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The api response.</returns>
public static async Task<ApiResponse<LoginInfo>> LogInAsync(string username, string password, string apiKey, CancellationToken cancellationToken)
public static async Task<ApiResponse<LoginInfo>> LogInAsync(string username, string password, CancellationToken cancellationToken)
{
var body = new { username, password };
var response = await RequestHandler.SendRequestAsync("/login", HttpMethod.Post, body, null, apiKey, 1, cancellationToken).ConfigureAwait(false);
var response = await RequestHandler.SendRequestAsync("/login", HttpMethod.Post, body, null, 1, cancellationToken).ConfigureAwait(false);

return new ApiResponse<LoginInfo>(response);
}
Expand All @@ -34,16 +33,15 @@ public static async Task<ApiResponse<LoginInfo>> LogInAsync(string username, str
/// Logout.
/// </summary>
/// <param name="user">The user information.</param>
/// <param name="apiKey">The api key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>logout status.</returns>
public static async Task<bool> LogOutAsync(LoginInfo user, string apiKey, CancellationToken cancellationToken)
public static async Task<bool> LogOutAsync(LoginInfo user, CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrEmpty(user.Token);

var headers = new Dictionary<string, string> { { "Authorization", user.Token } };

var response = await RequestHandler.SendRequestAsync("/logout", HttpMethod.Delete, null, headers, apiKey, 1, cancellationToken).ConfigureAwait(false);
var response = await RequestHandler.SendRequestAsync("/logout", HttpMethod.Delete, null, headers, 1, cancellationToken).ConfigureAwait(false);

return new ApiResponse<object>(response).Ok;
}
Expand All @@ -52,16 +50,15 @@ public static async Task<bool> LogOutAsync(LoginInfo user, string apiKey, Cancel
/// Get user info.
/// </summary>
/// <param name="user">The user information.</param>
/// <param name="apiKey">The api key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The encapsulated user info.</returns>
public static async Task<ApiResponse<EncapsulatedUserInfo>> GetUserInfo(LoginInfo user, string apiKey, CancellationToken cancellationToken)
public static async Task<ApiResponse<EncapsulatedUserInfo>> GetUserInfo(LoginInfo user, CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrEmpty(user.Token);

var headers = new Dictionary<string, string> { { "Authorization", user.Token } };

var response = await RequestHandler.SendRequestAsync("/infos/user", HttpMethod.Get, null, headers, apiKey, 1, cancellationToken).ConfigureAwait(false);
var response = await RequestHandler.SendRequestAsync("/infos/user", HttpMethod.Get, null, headers, 1, cancellationToken).ConfigureAwait(false);

return new ApiResponse<EncapsulatedUserInfo>(response);
}
Expand All @@ -72,22 +69,20 @@ public static async Task<ApiResponse<EncapsulatedUserInfo>> GetUserInfo(LoginInf
/// <param name="file">The subtitle file.</param>
/// <param name="format">The subtitle format.</param>
/// <param name="user">The user information.</param>
/// <param name="apiKey">The api key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The subtitle download info.</returns>
public static async Task<ApiResponse<SubtitleDownloadInfo>> GetSubtitleLinkAsync(
int file,
string format,
LoginInfo user,
string apiKey,
CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrEmpty(user.Token);

var headers = new Dictionary<string, string> { { "Authorization", user.Token } };

var body = new { file_id = file, sub_format = format };
var response = await RequestHandler.SendRequestAsync("/download", HttpMethod.Post, body, headers, apiKey, 1, cancellationToken).ConfigureAwait(false);
var response = await RequestHandler.SendRequestAsync("/download", HttpMethod.Post, body, headers, 1, cancellationToken).ConfigureAwait(false);

return new ApiResponse<SubtitleDownloadInfo>(response, $"file id: {file}");
}
Expand Down Expand Up @@ -118,10 +113,9 @@ public static async Task<HttpResponse> DownloadSubtitleAsync(string url, Cancell
/// Search for subtitle.
/// </summary>
/// <param name="options">The search options.</param>
/// <param name="apiKey">The api key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The list of response data.</returns>
public static async Task<ApiResponse<IReadOnlyList<ResponseData>>> SearchSubtitlesAsync(Dictionary<string, string> options, string apiKey, CancellationToken cancellationToken)
public static async Task<ApiResponse<IReadOnlyList<ResponseData>>> SearchSubtitlesAsync(Dictionary<string, string> options, CancellationToken cancellationToken)
{
var opts = new Dictionary<string, string>();
foreach (var (key, value) in options)
Expand All @@ -144,7 +138,7 @@ public static async Task<ApiResponse<IReadOnlyList<ResponseData>>> SearchSubtitl
}

var url = RequestHandler.AddQueryString("/subtitles", opts);
response = await RequestHandler.SendRequestAsync(url, HttpMethod.Get, null, null, apiKey, 1, cancellationToken).ConfigureAwait(false);
response = await RequestHandler.SendRequestAsync(url, HttpMethod.Get, null, null, 1, cancellationToken).ConfigureAwait(false);

last = new ApiResponse<SearchResult>(response, $"url: {url}", $"page: {current}");

Expand Down Expand Up @@ -175,12 +169,11 @@ public static async Task<ApiResponse<IReadOnlyList<ResponseData>>> SearchSubtitl
/// <summary>
/// Get language list.
/// </summary>
/// <param name="apiKey">The api key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The list of languages.</returns>
public static async Task<ApiResponse<EncapsulatedLanguageList>> GetLanguageList(string apiKey, CancellationToken cancellationToken)
public static async Task<ApiResponse<EncapsulatedLanguageList>> GetLanguageList(CancellationToken cancellationToken)
{
var response = await RequestHandler.SendRequestAsync("/infos/languages", HttpMethod.Get, null, null, apiKey, 1, cancellationToken).ConfigureAwait(false);
var response = await RequestHandler.SendRequestAsync("/infos/languages", HttpMethod.Get, null, null, 1, cancellationToken).ConfigureAwait(false);

return new ApiResponse<EncapsulatedLanguageList>(response);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public static class RequestHandler
/// <param name="method">The method.</param>
/// <param name="body">The request body.</param>
/// <param name="headers">The headers.</param>
/// <param name="apiKey">The api key.</param>
/// <param name="attempt">The request attempt key.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The response.</returns>
Expand All @@ -42,18 +41,12 @@ public static async Task<HttpResponse> SendRequestAsync(
HttpMethod method,
object? body,
Dictionary<string, string>? headers,
string? apiKey,
int attempt,
CancellationToken cancellationToken)
{
headers ??= new Dictionary<string, string>();

if (string.IsNullOrWhiteSpace(apiKey))
{
throw new ArgumentException("Provided API key is blank", nameof(apiKey));
}

headers.TryAdd("Api-Key", apiKey);
headers.TryAdd("Api-Key", OpenSubtitlesPlugin.ApiKey);
if (_hRemaining == 0)
{
await Task.Delay(1000 * _hReset, cancellationToken).ConfigureAwait(false);
Expand Down Expand Up @@ -98,14 +91,14 @@ public static async Task<HttpResponse> SendRequestAsync(

await Task.Delay(time * 1000, cancellationToken).ConfigureAwait(false);

return await SendRequestAsync(endpoint, method, body, headers, apiKey, attempt + 1, cancellationToken).ConfigureAwait(false);
return await SendRequestAsync(endpoint, method, body, headers, attempt + 1, cancellationToken).ConfigureAwait(false);
}

if (response.statusCode == HttpStatusCode.BadGateway && attempt <= 3)
{
await Task.Delay(500, cancellationToken).ConfigureAwait(false);

return await SendRequestAsync(endpoint, method, body, headers, apiKey, attempt + 1, cancellationToken).ConfigureAwait(false);
return await SendRequestAsync(endpoint, method, body, headers, attempt + 1, cancellationToken).ConfigureAwait(false);
}

if (!response.headers.TryGetValue("x-reason", out value))
Expand Down
6 changes: 3 additions & 3 deletions Jellyfin.Plugin.OpenSubtitles/OpenSubtitlesPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Jellyfin.Plugin.OpenSubtitles;
public class OpenSubtitlesPlugin : BasePlugin<PluginConfiguration>, IHasWebPages
{
/// <summary>
/// Default API key to use when performing an API call.
/// API key to use when performing an API call.
/// </summary>
public const string ApiKey = "gUCLWGoAg2PmyseoTM0INFFVPcDCeDlT";

Expand All @@ -30,10 +30,10 @@ public OpenSubtitlesPlugin(IApplicationPaths applicationPaths, IXmlSerializer xm

ConfigurationChanged += (_, _) =>
{
OpenSubtitleDownloader.Instance?.ConfigurationChanged(this.Configuration);
OpenSubtitleDownloader.Instance?.ConfigurationChanged(Configuration);
};

OpenSubtitleDownloader.Instance?.ConfigurationChanged(this.Configuration);
OpenSubtitleDownloader.Instance?.ConfigurationChanged(Configuration);
}

/// <inheritdoc />
Expand Down
10 changes: 2 additions & 8 deletions Jellyfin.Plugin.OpenSubtitles/Web/opensubtitles.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,8 @@ <h3 class="sectionTitle sectionTitle-cards"><b>In order for this plugin to work
<input is="emby-input" type="password" id="password" label="${LabelPassword}" />
<div class="fieldDescription">You can utilize this plugin by editing a library and modifying the options for subtitle downloads.</div>
</div>
<div class="inputContainer">
<input is="emby-input" type="password" id="apikey" label="(Optional) ${HeaderApiKey}:" />
<div class="fieldDescription">
You can provide an <a is="emby-linkbutton" class="button-link" target="_blank" href="https://www.opensubtitles.com/en/consumers">API Key</a> for doing API requests, if left empty the default API key will be used.
</div>
<div class="fieldDescription">
<a is="emby-linkbutton" class="button-link" target="_blank" href="https://92500a62-df9e-42ed-82a4-e6b3eeb89365.site.hbuptime.com/">OpenSubtitles API Status</a>
</div>
<div class="fieldDescription">
<a is="emby-linkbutton" class="button-link" target="_blank" href="https://92500a62-df9e-42ed-82a4-e6b3eeb89365.site.hbuptime.com/">OpenSubtitles API Status</a>
</div>
<div class="fieldDescription" id="ossresponse"></div>
<div>
Expand Down
Loading

0 comments on commit c3e0179

Please sign in to comment.