mirror of
https://github.com/knightcrawler-stremio/knightcrawler.git
synced 2024-12-20 03:29:51 +00:00
Run pre-commit
This commit is contained in:
@@ -16,16 +16,16 @@
|
||||
}
|
||||
},
|
||||
"WriteTo": [
|
||||
{
|
||||
{
|
||||
"Name": "Console",
|
||||
"Args": {
|
||||
"outputTemplate": "{Timestamp:HH:mm:ss} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
|
||||
"Properties": {
|
||||
"Application": "Metadata"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,41 +4,41 @@ public static class ConfigurationExtensions
|
||||
{
|
||||
private const string ConfigurationFolder = "Configuration";
|
||||
private const string LoggingConfig = "logging.json";
|
||||
|
||||
|
||||
public static IConfigurationBuilder AddServiceConfiguration(this IConfigurationBuilder configuration)
|
||||
{
|
||||
configuration.SetBasePath(Path.Combine(AppContext.BaseDirectory, ConfigurationFolder));
|
||||
|
||||
|
||||
configuration.AddJsonFile(LoggingConfig, false, true);
|
||||
|
||||
|
||||
configuration.AddEnvironmentVariables();
|
||||
|
||||
configuration.AddUserSecrets<Program>();
|
||||
|
||||
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
||||
public static TConfiguration LoadConfigurationFromConfig<TConfiguration>(this IServiceCollection services, IConfiguration configuration, string sectionName)
|
||||
where TConfiguration : class
|
||||
{
|
||||
var instance = configuration.GetSection(sectionName).Get<TConfiguration>();
|
||||
|
||||
|
||||
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
|
||||
|
||||
services.TryAddSingleton(instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
public static TConfiguration LoadConfigurationFromEnv<TConfiguration>(this IServiceCollection services)
|
||||
where TConfiguration : class
|
||||
{
|
||||
var instance = Activator.CreateInstance<TConfiguration>();
|
||||
|
||||
|
||||
ArgumentNullException.ThrowIfNull(instance, nameof(instance));
|
||||
|
||||
services.TryAddSingleton(instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ public static class EnvironmentExtensions
|
||||
public static bool GetEnvironmentVariableAsBool(this string prefix, string varName, bool fallback = false)
|
||||
{
|
||||
var fullVarName = GetFullVariableName(prefix, varName);
|
||||
|
||||
|
||||
var str = Environment.GetEnvironmentVariable(fullVarName);
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(str))
|
||||
{
|
||||
return fallback;
|
||||
@@ -21,11 +21,11 @@ public static class EnvironmentExtensions
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public static int GetEnvironmentVariableAsInt(this string prefix, string varName, int fallback = 0)
|
||||
{
|
||||
var fullVarName = GetFullVariableName(prefix, varName);
|
||||
|
||||
|
||||
var str = Environment.GetEnvironmentVariable(fullVarName);
|
||||
|
||||
if (string.IsNullOrEmpty(str))
|
||||
@@ -35,11 +35,11 @@ public static class EnvironmentExtensions
|
||||
|
||||
return int.TryParse(str, out var result) ? result : fallback;
|
||||
}
|
||||
|
||||
|
||||
public static string GetRequiredEnvironmentVariableAsString(this string prefix, string varName)
|
||||
{
|
||||
var fullVarName = GetFullVariableName(prefix, varName);
|
||||
|
||||
|
||||
var str = Environment.GetEnvironmentVariable(fullVarName);
|
||||
|
||||
if (string.IsNullOrEmpty(str))
|
||||
@@ -49,11 +49,11 @@ public static class EnvironmentExtensions
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
public static string GetOptionalEnvironmentVariableAsString(this string prefix, string varName, string? fallback = null)
|
||||
{
|
||||
var fullVarName = GetFullVariableName(prefix, varName);
|
||||
|
||||
|
||||
var str = Environment.GetEnvironmentVariable(fullVarName);
|
||||
|
||||
if (string.IsNullOrEmpty(str))
|
||||
@@ -63,6 +63,6 @@ public static class EnvironmentExtensions
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
private static string GetFullVariableName(string prefix, string varName) => $"{prefix}_{varName}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ namespace Metadata.Extensions;
|
||||
public static class JsonSerializerExtensions
|
||||
{
|
||||
public static string ToJson<T>(this T value) => JsonSerializer.Serialize(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ public static class ServiceCollectionExtensions
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
internal static IServiceCollection AddMongoDb(this IServiceCollection services)
|
||||
{
|
||||
services.LoadConfigurationFromEnv<MongoConfiguration>();
|
||||
services.AddTransient<ImdbMongoDbService>();
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
|
||||
internal static IServiceCollection AddJobSupport(this IServiceCollection services)
|
||||
{
|
||||
services.LoadConfigurationFromEnv<JobConfiguration>();
|
||||
@@ -24,7 +24,7 @@ public static class ServiceCollectionExtensions
|
||||
services.AddScheduler()
|
||||
.AddTransient<DownloadImdbDataJob>()
|
||||
.AddHostedService<JobScheduler>();
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ internal static class WebApplicationBuilderExtensions
|
||||
{
|
||||
options.DefaultExecutionTimeout = 6.Hours();
|
||||
});
|
||||
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ public class JobConfiguration
|
||||
private const string DownloadImdbDataVariable = "DOWNLOAD_IMDB_DATA_SCHEDULE";
|
||||
private const string DownloadImdbDataOnceVariable = "DOWNLOAD_IMDB_DATA_ONCE";
|
||||
private const string InsertBatchSizeVariable = "INSERT_BATCH_SIZE";
|
||||
|
||||
|
||||
public int InsertBatchSize { get; init; } = Prefix.GetEnvironmentVariableAsInt(InsertBatchSizeVariable, 25_000);
|
||||
public string DownloadImdbCronSchedule { get; init; } = Prefix.GetOptionalEnvironmentVariableAsString(DownloadImdbDataVariable, CronExpressions.EveryHour);
|
||||
public bool DownloadImdbOnce { get; init; } = Prefix.GetEnvironmentVariableAsBool(DownloadImdbDataOnceVariable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ public class MongoConfiguration
|
||||
private const string DbVariable = "DB";
|
||||
private const string UsernameVariable = "USER";
|
||||
private const string PasswordVariable = "PASSWORD";
|
||||
|
||||
|
||||
|
||||
private string Host { get; init; } = Prefix.GetRequiredEnvironmentVariableAsString(HostVariable);
|
||||
private int Port { get; init; } = Prefix.GetEnvironmentVariableAsInt(PortVariable, 27017);
|
||||
private string Username { get; init; } = Prefix.GetRequiredEnvironmentVariableAsString(UsernameVariable);
|
||||
private string Password { get; init; } = Prefix.GetRequiredEnvironmentVariableAsString(PasswordVariable);
|
||||
public string DbName { get; init; } = Prefix.GetRequiredEnvironmentVariableAsString(DbVariable);
|
||||
|
||||
|
||||
public string ConnectionString => $"mongodb://{Username}:{Password}@{Host}:{Port}/{DbName}?tls=false&directConnection=true&authSource=admin";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Metadata.Features.DeleteDownloadedImdbData;
|
||||
|
||||
public record DeleteDownloadedImdbDataRequest(string FilePath);
|
||||
public record DeleteDownloadedImdbDataRequest(string FilePath);
|
||||
|
||||
@@ -5,9 +5,9 @@ public class DeleteDownloadedImdbDataRequestHandler(ILogger<DeleteDownloadedImdb
|
||||
public Task Handle(DeleteDownloadedImdbDataRequest request, CancellationToken _)
|
||||
{
|
||||
logger.LogInformation("Deleting file {FilePath}", request.FilePath);
|
||||
|
||||
|
||||
File.Delete(request.FilePath);
|
||||
|
||||
|
||||
logger.LogInformation("File Deleted");
|
||||
|
||||
if (configuration.DownloadImdbOnce)
|
||||
@@ -18,4 +18,4 @@ public class DeleteDownloadedImdbDataRequestHandler(ILogger<DeleteDownloadedImdb
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ public class DownloadImdbDataJob(IMessageBus messageBus, JobConfiguration config
|
||||
public override bool IsScheduelable => !configuration.DownloadImdbOnce && !string.IsNullOrEmpty(configuration.DownloadImdbCronSchedule);
|
||||
public override string JobName => nameof(DownloadImdbDataJob);
|
||||
public override async Task Invoke() => await messageBus.SendAsync(new GetImdbDataRequest());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Metadata.Features.DownloadImdbData;
|
||||
|
||||
public record GetImdbDataRequest;
|
||||
public record GetImdbDataRequest;
|
||||
|
||||
@@ -3,28 +3,28 @@ namespace Metadata.Features.DownloadImdbData;
|
||||
public class GetImdbDataRequestHandler(IHttpClientFactory clientFactory, ILogger<GetImdbDataRequestHandler> logger)
|
||||
{
|
||||
private const string TitleBasicsFileName = "title.basics.tsv";
|
||||
|
||||
|
||||
public async Task<ImportImdbDataRequest> Handle(GetImdbDataRequest _, CancellationToken cancellationToken)
|
||||
{
|
||||
logger.LogInformation("Downloading IMDB data");
|
||||
|
||||
|
||||
var client = clientFactory.CreateClient("imdb-data");
|
||||
var response = await client.GetAsync($"{TitleBasicsFileName}.gz", cancellationToken);
|
||||
|
||||
|
||||
var tempFile = Path.Combine(Path.GetTempPath(), TitleBasicsFileName);
|
||||
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
|
||||
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
await using var gzipStream = new GZipStream(stream, CompressionMode.Decompress);
|
||||
await using var fileStream = File.Create(tempFile);
|
||||
|
||||
|
||||
await gzipStream.CopyToAsync(fileStream, cancellationToken);
|
||||
|
||||
|
||||
logger.LogInformation("Downloaded IMDB data to {TempFile}", tempFile);
|
||||
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
return new(tempFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ public class ImdbEntry
|
||||
public string? EndYear { get; set; }
|
||||
public string? RuntimeMinutes { get; set; }
|
||||
public string? Genres { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ public class ImdbMongoDbService
|
||||
public ImdbMongoDbService(MongoConfiguration configuration, ILogger<ImdbMongoDbService> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
|
||||
|
||||
var client = new MongoClient(configuration.ConnectionString);
|
||||
var database = client.GetDatabase(configuration.DbName);
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ImdbMongoDbService
|
||||
|
||||
await _imdbCollection.BulkWriteAsync(operations);
|
||||
}
|
||||
|
||||
|
||||
public bool IsDatabaseInitialized()
|
||||
{
|
||||
try
|
||||
@@ -61,4 +61,4 @@ public class ImdbMongoDbService
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
namespace Metadata.Features.ImportImdbData;
|
||||
|
||||
public record ImportImdbDataRequest(string FilePath);
|
||||
public record ImportImdbDataRequest(string FilePath);
|
||||
|
||||
@@ -21,16 +21,16 @@ public class ImportImdbDataRequestHandler(ILogger<ImportImdbDataRequestHandler>
|
||||
FullMode = BoundedChannelFullMode.Wait,
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Skip the header row
|
||||
await csv.ReadAsync();
|
||||
|
||||
|
||||
var batchInsertTask = CreateBatchOfEntries(channel, cancellationToken);
|
||||
|
||||
await ReadEntries(csv, channel, cancellationToken);
|
||||
|
||||
channel.Writer.Complete();
|
||||
|
||||
|
||||
await batchInsertTask;
|
||||
|
||||
return new(request.FilePath);
|
||||
@@ -45,7 +45,7 @@ public class ImportImdbDataRequestHandler(ILogger<ImportImdbDataRequestHandler>
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var batch = new List<ImdbEntry>
|
||||
{
|
||||
movieData,
|
||||
@@ -63,7 +63,7 @@ public class ImportImdbDataRequestHandler(ILogger<ImportImdbDataRequestHandler>
|
||||
}
|
||||
}
|
||||
}, cancellationToken);
|
||||
|
||||
|
||||
private static async Task ReadEntries(CsvReader csv, Channel<ImdbEntry, ImdbEntry> channel, CancellationToken cancellationToken)
|
||||
{
|
||||
while (await csv.ReadAsync())
|
||||
@@ -80,13 +80,13 @@ public class ImportImdbDataRequestHandler(ILogger<ImportImdbDataRequestHandler>
|
||||
RuntimeMinutes = csv.GetField(7),
|
||||
Genres = csv.GetField(8),
|
||||
};
|
||||
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await channel.Writer.WriteAsync(movieData, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,6 @@ public abstract class BaseJob : IMetadataJob
|
||||
public abstract bool IsScheduelable { get; }
|
||||
|
||||
public abstract string JobName { get; }
|
||||
|
||||
|
||||
public abstract Task Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ public interface IMetadataJob : IInvocable
|
||||
{
|
||||
bool IsScheduelable { get; }
|
||||
string JobName { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,14 @@ public class JobScheduler(IServiceProvider serviceProvider) : IHostedService
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using var scope = serviceProvider.CreateAsyncScope();
|
||||
|
||||
|
||||
var mongoDbService = scope.ServiceProvider.GetRequiredService<ImdbMongoDbService>();
|
||||
|
||||
|
||||
if (!mongoDbService.IsDatabaseInitialized())
|
||||
{
|
||||
throw new InvalidOperationException("MongoDb is not initialized");
|
||||
}
|
||||
|
||||
|
||||
var jobConfigurations = scope.ServiceProvider.GetRequiredService<JobConfiguration>();
|
||||
var downloadJob = scope.ServiceProvider.GetRequiredService<DownloadImdbDataJob>();
|
||||
|
||||
@@ -20,15 +20,15 @@ public class JobScheduler(IServiceProvider serviceProvider) : IHostedService
|
||||
{
|
||||
return downloadJob.Invoke();
|
||||
}
|
||||
|
||||
|
||||
var scheduler = scope.ServiceProvider.GetRequiredService<IScheduler>();
|
||||
|
||||
|
||||
scheduler.Schedule<DownloadImdbDataJob>()
|
||||
.Cron(jobConfigurations.DownloadImdbCronSchedule)
|
||||
.PreventOverlapping(nameof(downloadJob.JobName));
|
||||
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ public static class CronExpressions
|
||||
public const string EveryDay = "0 0 0 * *";
|
||||
public const string EveryWeek = "0 0 * * 0";
|
||||
public const string EveryMonth = "0 0 0 * *";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ public static class HttpClients
|
||||
{
|
||||
public const string ImdbDataClientName = "imdb-data";
|
||||
public const string ImdbClientBaseAddress = "https://datasets.imdbws.com/";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@ builder.Services
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
await host.RunAsync();
|
||||
await host.RunAsync();
|
||||
|
||||
@@ -1 +1 @@
|
||||
*.ts
|
||||
*.ts
|
||||
|
||||
@@ -36,4 +36,4 @@ module.exports = {
|
||||
"one-var": ["error", { uninitialized: "consecutive" }],
|
||||
"prefer-destructuring": "warn",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
docker build -t ippexdeploymentscr.azurecr.io/dave/stremio-addon-jackett:latest . --platform linux/amd64
|
||||
docker push ippexdeploymentscr.azurecr.io/dave/stremio-addon-jackett:latest
|
||||
docker push ippexdeploymentscr.azurecr.io/dave/stremio-addon-jackett:latest
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
"typeRoots": ["node_modules/@types", "src/@types"]
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,12 +22,12 @@ builder.defineStreamHandler((args) => {
|
||||
if (!args.id.match(/tt\d+/i) && !args.id.match(/kitsu:\d+/i)) {
|
||||
return Promise.resolve({ streams: [] });
|
||||
}
|
||||
|
||||
|
||||
if (processConfig.DEBUG) {
|
||||
console.log(`Incoming stream ${args.id} request`)
|
||||
console.log('args', args);
|
||||
}
|
||||
|
||||
|
||||
return cacheWrapStream(args.id, () => limiter.schedule(() =>
|
||||
streamHandler(args)
|
||||
.then(records => records.map(record => toStreamInfo(record, args.type))))
|
||||
|
||||
@@ -111,7 +111,7 @@ export const transformData = async (data, query) => {
|
||||
console.log("Transforming data for query " + data);
|
||||
|
||||
let results = [];
|
||||
|
||||
|
||||
const parsedData = await parseString(data);
|
||||
|
||||
if (!parsedData.rss.channel[0]?.item) {
|
||||
@@ -126,7 +126,7 @@ export const transformData = async (data, query) => {
|
||||
[torznabDataItem.$.name]: torznabDataItem.$.value,
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
if (torznabData.infohash) {
|
||||
|
||||
const [title, pubDate, category, size] = [rssItem.title[0], rssItem.pubDate[0], rssItem.category[0], rssItem.size[0]];
|
||||
@@ -148,4 +148,4 @@ export const transformData = async (data, query) => {
|
||||
|
||||
|
||||
return results;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -38,4 +38,4 @@ export const searchJackett = async (query) => {
|
||||
}
|
||||
|
||||
return sortedResults;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,7 +18,7 @@ const getMovieSearchQueries = (cleanName, year) => {
|
||||
const getSeriesSearchQueries = (cleanName, year, season, episode) => {
|
||||
return {
|
||||
seriesByEpisode: seriesByEpisode(cleanName, season, episode),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export const jackettSearchQueries = (cleanName, type, year, season, episode) => {
|
||||
@@ -27,8 +27,8 @@ export const jackettSearchQueries = (cleanName, type, year, season, episode) =>
|
||||
return getMovieSearchQueries(cleanName, year);
|
||||
case Type.SERIES:
|
||||
return getSeriesSearchQueries(cleanName, year, season, episode);
|
||||
|
||||
|
||||
default:
|
||||
return { };
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ const cinemetaUri = cinemetaConfig.URI;
|
||||
export const getMetaData = (args) => {
|
||||
const [imdbId] = args.id.split(':');
|
||||
const {type} = args;
|
||||
|
||||
|
||||
return cacheWrapImdbMetaData(args.id, () => getInfoForImdbId(imdbId, type));
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ const getInfoForImdbId = async (imdbId, type) => {
|
||||
console.log(`Getting info for ${imdbId} of type ${type}`);
|
||||
console.log(`Request URI: ${requestUri}`);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const { data: response } = await axios.get(requestUri, options);
|
||||
return response.meta;
|
||||
@@ -28,4 +28,4 @@ const getInfoForImdbId = async (imdbId, type) => {
|
||||
console.log(error);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -22,4 +22,4 @@ export function parseConfiguration(configuration) {
|
||||
.map(value => keysToUppercase.includes(key) ? value.toUpperCase() : value.toLowerCase()))
|
||||
|
||||
return configValues;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ a.install-link {
|
||||
}
|
||||
|
||||
.input:focus, .btn:focus {
|
||||
outline: none;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2pt rgb(30, 144, 255, 0.7);
|
||||
}
|
||||
`;
|
||||
@@ -210,7 +210,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
const debridOptionsHTML = Object.values(DebridOptions.options)
|
||||
.map(option => `<option value="${option.key}">${option.description}</option>`)
|
||||
.join('\n');
|
||||
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html style="background-image: url(${background});">
|
||||
@@ -239,54 +239,54 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
<h2 class="description">${manifest.description || ''}</h2>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
|
||||
<label class="label" id="iLimitLabel" for="iLimit">Max results per quality:</label>
|
||||
<input type="text" inputmode="numeric" pattern="[0-9]*" id="iLimit" onchange="generateInstallLink()" class="input" placeholder="All results">
|
||||
|
||||
|
||||
<label class="label" for="iDebridProviders">Debrid provider:</label>
|
||||
<select id="iDebridProviders" class="input" onchange="debridProvidersChange()">
|
||||
<option value="none" selected>None</option>
|
||||
${debridProvidersHTML}
|
||||
</select>
|
||||
|
||||
|
||||
<div id="dRealDebrid">
|
||||
<label class="label" for="iRealDebrid">RealDebrid API Key (Find it <a href='https://real-debrid.com/apitoken' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iRealDebrid" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dAllDebrid">
|
||||
<label class="label" for="iAllDebrid">AllDebrid API Key (Create it <a href='https://alldebrid.com/apikeys' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iAllDebrid" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dPremiumize">
|
||||
<label class="label" for="iPremiumize">Premiumize API Key (Find it <a href='https://www.premiumize.me/account' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iPremiumize" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dDebridLink">
|
||||
<label class="label" for="iDebridLink">DebridLink API Key (Find it <a href='https://debrid-link.fr/webapp/apikey' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iDebridLink" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dOffcloud">
|
||||
<label class="label" for="iOffcloud">Offcloud API Key (Find it <a href='https://offcloud.com/#/account' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iOffcloud" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dPutio">
|
||||
<label class="label" for="iPutio">Put.io ClientId and Token (Create new OAuth App <a href='https://app.put.io/oauth' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iPutioClientId" placeholder="ClientId" onchange="generateInstallLink()" class="input">
|
||||
<input type="text" id="iPutioToken" placeholder="Token" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dDebridOptions">
|
||||
<label class="label" for="iDebridOptions">Debrid options:</label>
|
||||
<select id="iDebridOptions" class="input" onchange="generateInstallLink()" name="debridOptions[]" multiple="multiple">
|
||||
${debridOptionsHTML}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<a id="installLink" class="install-link" href="#">
|
||||
@@ -295,7 +295,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
<div class="contact">
|
||||
<p>Or paste into Stremio search bar after clicking install</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="separator"></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
@@ -304,7 +304,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
const isTvAgent = /\\b(?:tv|wv)\\b/i.test(navigator.userAgent)
|
||||
const isDesktopMedia = window.matchMedia("(pointer:fine)").matches;
|
||||
if (isDesktopMedia && !isTvMedia && !isTvAgent) {
|
||||
$('#iDebridOptions').multiselect({
|
||||
$('#iDebridOptions').multiselect({
|
||||
nonSelectedText: 'None',
|
||||
buttonTextAlignment: 'left',
|
||||
onChange: () => generateInstallLink()
|
||||
@@ -325,7 +325,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
generateInstallLink();
|
||||
debridProvidersChange();
|
||||
});
|
||||
|
||||
|
||||
function debridProvidersChange() {
|
||||
const provider = $('#iDebridProviders').val()
|
||||
$('#dDebridOptions').toggle(provider !== 'none');
|
||||
@@ -336,10 +336,10 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
$('#dOffcloud').toggle(provider === '${MochOptions.offcloud.key}');
|
||||
$('#dPutio').toggle(provider === '${MochOptions.putio.key}');
|
||||
}
|
||||
|
||||
|
||||
function generateInstallLink() {
|
||||
const limitValue = $('#iLimit').val() || '';
|
||||
|
||||
|
||||
const debridOptionsValue = $('#iDebridOptions').val().join(',') || '';
|
||||
const realDebridValue = $('#iRealDebrid').val() || '';
|
||||
const allDebridValue = $('#iAllDebrid').val() || '';
|
||||
@@ -348,9 +348,9 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
const offcloudValue = $('#iOffcloud').val() || ''
|
||||
const putioClientIdValue = $('#iPutioClientId').val() || '';
|
||||
const putioTokenValue = $('#iPutioToken').val() || '';
|
||||
|
||||
|
||||
const limit = /^[1-9][0-9]{0,2}$/.test(limitValue) && limitValue;
|
||||
|
||||
|
||||
const debridOptions = debridOptionsValue.length && debridOptionsValue.trim();
|
||||
const realDebrid = realDebridValue.length && realDebridValue.trim();
|
||||
const premiumize = premiumizeValue.length && premiumizeValue.trim();
|
||||
@@ -361,7 +361,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
|
||||
let configurationValue = [
|
||||
['limit', limit],
|
||||
['${DebridOptions.key}', debridOptions],
|
||||
['${DebridOptions.key}', debridOptions],
|
||||
['${MochOptions.realdebrid.key}', realDebrid],
|
||||
['${MochOptions.premiumize.key}', premiumize],
|
||||
['${MochOptions.alldebrid.key}', allDebrid],
|
||||
|
||||
@@ -56,4 +56,4 @@ export function getSources(magnetInfo) {
|
||||
}
|
||||
const trackers = Array.isArray(magnetInfo.announce) ? magnetInfo.announce : magnetInfo.announce.split(',');
|
||||
return trackers.map(tracker => `tracker:${tracker}`).concat(`dht:${magnetInfo.infohash}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,4 +39,4 @@ export const cacheConfig = {
|
||||
STALE_REVALIDATE_AGE: parseInt(process.env.STALE_REVALIDATE_AGE) || 4 * 60 * 60, // 4 hours
|
||||
STALE_ERROR_AGE: parseInt(process.env.STALE_ERROR_AGE) || 7 * 24 * 60 * 60, // 7 days
|
||||
GLOBAL_KEY_PREFIX: process.env.GLOBAL_KEY_PREFIX || 'jackettio-addon',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function toStreamInfo(record, type) {
|
||||
const behaviorHints = bingeGroup ? { bingeGroup } : undefined;
|
||||
|
||||
const magnetInfo = decode(record.magneturl)
|
||||
|
||||
|
||||
return cleanOutputObject({
|
||||
name: name,
|
||||
title: title,
|
||||
@@ -61,7 +61,7 @@ function formatSize(size) {
|
||||
function getBingeGroupParts(record, sameInfo, quality, torrentInfo, fileInfo, type) {
|
||||
if (type === Type.MOVIE) {
|
||||
return [quality];
|
||||
|
||||
|
||||
} else if (sameInfo) {
|
||||
return [quality];
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ export const Type = {
|
||||
SERIES: 'series',
|
||||
ANIME: 'anime',
|
||||
OTHER: 'other'
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,4 +13,4 @@ export function isStaticUrl(url) {
|
||||
return Object.values(staticVideoUrls).some(videoUrl => url?.endsWith(videoUrl));
|
||||
}
|
||||
|
||||
export default staticVideoUrls
|
||||
export default staticVideoUrls
|
||||
|
||||
@@ -1 +1 @@
|
||||
*.ts
|
||||
*.ts
|
||||
|
||||
@@ -36,4 +36,4 @@ module.exports = {
|
||||
"one-var": ["error", { uninitialized: "consecutive" }],
|
||||
"prefer-destructuring": "warn",
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,4 +11,4 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -65,4 +65,4 @@ try {
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,4 @@
|
||||
"typeRoots": ["node_modules/@types", "src/@types"]
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ builder.defineStreamHandler((args) => {
|
||||
if (!args.id.match(/tt\d+/i) && !args.id.match(/kitsu:\d+/i)) {
|
||||
return Promise.resolve({ streams: [] });
|
||||
}
|
||||
|
||||
|
||||
return cacheWrapStream(args.id, () => limiter.schedule(() =>
|
||||
streamHandler(args)
|
||||
.then(records => records
|
||||
|
||||
@@ -25,4 +25,4 @@ export function parseConfiguration(configuration) {
|
||||
.map(value => keysToUppercase.includes(key) ? value.toUpperCase() : value.toLowerCase()))
|
||||
|
||||
return configValues;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ a.install-link {
|
||||
}
|
||||
|
||||
.input:focus, .btn:focus {
|
||||
outline: none;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 2pt rgb(30, 144, 255, 0.7);
|
||||
}
|
||||
`;
|
||||
@@ -228,7 +228,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
.join('\n');
|
||||
const stylizedTypes = manifest.types
|
||||
.map(t => t[0].toUpperCase() + t.slice(1) + (t !== 'series' ? 's' : ''));
|
||||
|
||||
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html style="background-image: url(${background});">
|
||||
@@ -264,73 +264,73 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
</ul>
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
|
||||
<label class="label" for="iSort">Sorting:</label>
|
||||
<select id="iSort" class="input" onchange="sortModeChange()">
|
||||
${sortOptionsHTML}
|
||||
</select>
|
||||
|
||||
|
||||
<label class="label" for="iLanguages">Priority foreign language:</label>
|
||||
<select id="iLanguages" class="input" onchange="generateInstallLink()" name="languages[]" multiple="multiple" title="Streams with the selected dubs/subs language will be shown on the top">
|
||||
${languagesOptionsHTML}
|
||||
</select>
|
||||
|
||||
|
||||
<label class="label" for="iQualityFilter">Exclude qualities/resolutions:</label>
|
||||
<select id="iQualityFilter" class="input" onchange="generateInstallLink()" name="qualityFilters[]" multiple="multiple">
|
||||
${qualityFiltersHTML}
|
||||
</select>
|
||||
|
||||
|
||||
<label class="label" id="iLimitLabel" for="iLimit">Max results per quality:</label>
|
||||
<input type="text" inputmode="numeric" pattern="[0-9]*" id="iLimit" onchange="generateInstallLink()" class="input" placeholder="All results">
|
||||
|
||||
|
||||
<label class="label" id="iSizeFilterLabel" for="iSizeFilter">Video size limit:</label>
|
||||
<input type="text" pattern="([0-9.]*(?:MB|GB),?)+" id="iSizeFilter" onchange="generateInstallLink()" class="input" placeholder="No limit" title="Returned videos cannot exceed this size, use comma to have different size for movies and series. Examples: 5GB ; 800MB ; 10GB,2GB">
|
||||
|
||||
|
||||
|
||||
|
||||
<label class="label" for="iDebridProviders">Debrid provider:</label>
|
||||
<select id="iDebridProviders" class="input" onchange="debridProvidersChange()">
|
||||
<option value="none" selected>None</option>
|
||||
${debridProvidersHTML}
|
||||
</select>
|
||||
|
||||
|
||||
<div id="dRealDebrid">
|
||||
<label class="label" for="iRealDebrid">RealDebrid API Key (Find it <a href='https://real-debrid.com/apitoken' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iRealDebrid" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dAllDebrid">
|
||||
<label class="label" for="iAllDebrid">AllDebrid API Key (Create it <a href='https://alldebrid.com/apikeys' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iAllDebrid" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dPremiumize">
|
||||
<label class="label" for="iPremiumize">Premiumize API Key (Find it <a href='https://www.premiumize.me/account' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iPremiumize" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dDebridLink">
|
||||
<label class="label" for="iDebridLink">DebridLink API Key (Find it <a href='https://debrid-link.fr/webapp/apikey' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iDebridLink" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dOffcloud">
|
||||
<label class="label" for="iOffcloud">Offcloud API Key (Find it <a href='https://offcloud.com/#/account' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iOffcloud" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dPutio">
|
||||
<label class="label" for="iPutio">Put.io ClientId and Token (Create new OAuth App <a href='https://app.put.io/oauth' target="_blank">here</a>):</label>
|
||||
<input type="text" id="iPutioClientId" placeholder="ClientId" onchange="generateInstallLink()" class="input">
|
||||
<input type="text" id="iPutioToken" placeholder="Token" onchange="generateInstallLink()" class="input">
|
||||
</div>
|
||||
|
||||
|
||||
<div id="dDebridOptions">
|
||||
<label class="label" for="iDebridOptions">Debrid options:</label>
|
||||
<select id="iDebridOptions" class="input" onchange="generateInstallLink()" name="debridOptions[]" multiple="multiple">
|
||||
${debridOptionsHTML}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="separator"></div>
|
||||
|
||||
<a id="installLink" class="install-link" href="#">
|
||||
@@ -339,7 +339,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
<div class="contact">
|
||||
<p>Or paste into Stremio search bar after clicking install</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="separator"></div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
@@ -348,19 +348,19 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
const isTvAgent = /\\b(?:tv|wv)\\b/i.test(navigator.userAgent)
|
||||
const isDesktopMedia = window.matchMedia("(pointer:fine)").matches;
|
||||
if (isDesktopMedia && !isTvMedia && !isTvAgent) {
|
||||
$('#iLanguages').multiselect({
|
||||
$('#iLanguages').multiselect({
|
||||
nonSelectedText: 'None',
|
||||
buttonTextAlignment: 'left',
|
||||
onChange: () => generateInstallLink()
|
||||
});
|
||||
$('#iLanguages').multiselect('select', [${languages.map(language => '"' + language + '"')}]);
|
||||
$('#iQualityFilter').multiselect({
|
||||
$('#iQualityFilter').multiselect({
|
||||
nonSelectedText: 'None',
|
||||
buttonTextAlignment: 'left',
|
||||
onChange: () => generateInstallLink()
|
||||
});
|
||||
$('#iQualityFilter').multiselect('select', [${qualityFilters.map(filter => '"' + filter + '"')}]);
|
||||
$('#iDebridOptions').multiselect({
|
||||
$('#iDebridOptions').multiselect({
|
||||
nonSelectedText: 'None',
|
||||
buttonTextAlignment: 'left',
|
||||
onChange: () => generateInstallLink()
|
||||
@@ -385,7 +385,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
generateInstallLink();
|
||||
debridProvidersChange();
|
||||
});
|
||||
|
||||
|
||||
function sortModeChange() {
|
||||
if (['${SortOptions.options.seeders.key}', '${SortOptions.options.size.key}'].includes($('#iSort').val())) {
|
||||
$("#iLimitLabel").text("Max results:");
|
||||
@@ -394,7 +394,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
}
|
||||
generateInstallLink();
|
||||
}
|
||||
|
||||
|
||||
function debridProvidersChange() {
|
||||
const provider = $('#iDebridProviders').val()
|
||||
$('#dDebridOptions').toggle(provider !== 'none');
|
||||
@@ -405,14 +405,14 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
$('#dOffcloud').toggle(provider === '${MochOptions.offcloud.key}');
|
||||
$('#dPutio').toggle(provider === '${MochOptions.putio.key}');
|
||||
}
|
||||
|
||||
|
||||
function generateInstallLink() {
|
||||
const qualityFilterValue = $('#iQualityFilter').val().join(',') || '';
|
||||
const sortValue = $('#iSort').val() || '';
|
||||
const languagesValue = $('#iLanguages').val().join(',') || [];
|
||||
const limitValue = $('#iLimit').val() || '';
|
||||
const sizeFilterValue = $('#iSizeFilter').val() || '';
|
||||
|
||||
|
||||
const debridOptionsValue = $('#iDebridOptions').val().join(',') || '';
|
||||
const realDebridValue = $('#iRealDebrid').val() || '';
|
||||
const allDebridValue = $('#iAllDebrid').val() || '';
|
||||
@@ -421,13 +421,13 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
const offcloudValue = $('#iOffcloud').val() || ''
|
||||
const putioClientIdValue = $('#iPutioClientId').val() || '';
|
||||
const putioTokenValue = $('#iPutioToken').val() || '';
|
||||
|
||||
|
||||
const qualityFilters = qualityFilterValue.length && qualityFilterValue;
|
||||
const sort = sortValue !== '${SortOptions.options.qualitySeeders.key}' && sortValue;
|
||||
const languages = languagesValue.length && languagesValue;
|
||||
const limit = /^[1-9][0-9]{0,2}$/.test(limitValue) && limitValue;
|
||||
const sizeFilter = sizeFilterValue.length && sizeFilterValue;
|
||||
|
||||
|
||||
const debridOptions = debridOptionsValue.length && debridOptionsValue.trim();
|
||||
const realDebrid = realDebridValue.length && realDebridValue.trim();
|
||||
const premiumize = premiumizeValue.length && premiumizeValue.trim();
|
||||
@@ -442,7 +442,7 @@ export default function landingTemplate(manifest, config = {}) {
|
||||
['${QualityFilter.key}', qualityFilters],
|
||||
['limit', limit],
|
||||
['${SizeFilter.key}', sizeFilter],
|
||||
['${DebridOptions.key}', debridOptions],
|
||||
['${DebridOptions.key}', debridOptions],
|
||||
['${MochOptions.realdebrid.key}', realDebrid],
|
||||
['${MochOptions.premiumize.key}', premiumize],
|
||||
['${MochOptions.alldebrid.key}', allDebrid],
|
||||
|
||||
@@ -85,4 +85,4 @@ export function getSources(trackersInput, infoHash) {
|
||||
|
||||
function unique(array) {
|
||||
return Array.from(new Set(array));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function sortStreams(streams, config) {
|
||||
|
||||
function _sortStreams(streams, config) {
|
||||
const limit = /^[1-9][0-9]*$/.test(config.limit) && parseInt(config.limit) || undefined;
|
||||
|
||||
|
||||
return sortBySize(streams, limit);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,4 +3,4 @@ export const Type = {
|
||||
SERIES: 'series',
|
||||
ANIME: 'anime',
|
||||
OTHER: 'other'
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,4 +13,4 @@ export function isStaticUrl(url) {
|
||||
return Object.values(staticVideoUrls).some(videoUrl => url?.endsWith(videoUrl));
|
||||
}
|
||||
|
||||
export default staticVideoUrls
|
||||
export default staticVideoUrls
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
dist/
|
||||
esbuild.ts
|
||||
jest.config.ts
|
||||
jest.config.ts
|
||||
|
||||
@@ -81,4 +81,4 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
v20.10.0
|
||||
v20.10.0
|
||||
|
||||
@@ -44,4 +44,4 @@ try {
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ export default {
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'ts-jest',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export enum CacheType {
|
||||
Memory = 'memory',
|
||||
MongoDb = 'mongodb'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ export enum TorrentType {
|
||||
Series = 'Series',
|
||||
Movie = 'Movie',
|
||||
Anime = 'anime',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ export const BooleanHelpers = {
|
||||
throw new Error(`Invalid boolean value: '${value}'. Allowed values are 'true', 'false', 'yes', 'no', '1', or '0'.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,4 +63,4 @@ export const ExtensionHelpers = {
|
||||
const extensionMatch = filename.match(/\.(\w{2,4})$/);
|
||||
return extensionMatch !== null && extensions.includes(extensionMatch[1].toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,4 +34,4 @@ export const PromiseHelpers = {
|
||||
return array.sort((a, b) => array.filter(v => v === a).length - array.filter(v => v === b).length).pop();
|
||||
}
|
||||
};
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export interface ICacheOptions {
|
||||
ttl: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@ export interface ICacheService {
|
||||
cacheTrackers: (method: CacheMethod) => Promise<any>;
|
||||
}
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
@@ -81,4 +81,4 @@ export interface ICinemetaLink {
|
||||
export interface ICinemetaBehaviorHints {
|
||||
defaultVideoId?: null;
|
||||
hasScheduledVideos?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ export interface ICommonVideoMetadata {
|
||||
name?: string;
|
||||
id?: string;
|
||||
imdb_id?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ export interface IIngestedRabbitTorrent {
|
||||
|
||||
export interface IIngestedRabbitMessage {
|
||||
message: IIngestedRabbitTorrent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@ export interface IKitsuCatalogMetaData {
|
||||
background: string;
|
||||
trailers: IKitsuTrailer[];
|
||||
links: IKitsuLink[];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,4 +46,4 @@ export interface IKitsuLink {
|
||||
name?: string;
|
||||
category?: string;
|
||||
url?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,4 +9,4 @@ export interface ILoggingService {
|
||||
warn(message: string, ...args: any[]): void;
|
||||
}
|
||||
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
|
||||
@@ -6,4 +6,4 @@ export interface IMetaDataQuery {
|
||||
season?: number
|
||||
episode?: number
|
||||
id?: string | number
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ export interface IMetadataResponse {
|
||||
videos?: ICommonVideoMetadata[];
|
||||
episodeCount?: number[];
|
||||
totalCount?: number;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,4 +11,4 @@ export interface IMetadataService {
|
||||
isEpisodeImdbId(imdbId: string | undefined): Promise<boolean>;
|
||||
|
||||
escapeTitle(title: string): string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,4 +33,4 @@ export interface IParseTorrentTitleResult {
|
||||
videoFile?: IFileAttributes;
|
||||
folderName?: string;
|
||||
fileName?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ export interface IParsedTorrent extends IParseTorrentTitleResult {
|
||||
seeders?: number;
|
||||
torrentId?: string;
|
||||
fileCollection?: ITorrentFileCollection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export interface IProcessTorrentsJob {
|
||||
listenToQueue: () => Promise<void>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ import {ITorrentFileCollection} from "@interfaces/torrent_file_collection";
|
||||
|
||||
export interface ITorrentDownloadService {
|
||||
getTorrentFiles(torrent: IParsedTorrent, timeout: number): Promise<ITorrentFileCollection>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ export interface ITorrentEntriesService {
|
||||
createTorrentContents(torrent: Torrent): Promise<void>;
|
||||
|
||||
updateTorrentSeeders(torrent: ITorrentAttributes): Promise<[number] | undefined>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,4 +6,4 @@ export interface ITorrentFileCollection {
|
||||
contents?: IContentAttributes[];
|
||||
videos?: IFileAttributes[];
|
||||
subtitles?: ISubtitleAttributes[];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ export interface ITorrentFileService {
|
||||
parseTorrentFiles(torrent: IParsedTorrent): Promise<ITorrentFileCollection>;
|
||||
|
||||
isPackTorrent(torrent: IParsedTorrent): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ import {IIngestedTorrentAttributes} from "@repository/interfaces/ingested_torren
|
||||
|
||||
export interface ITorrentProcessingService {
|
||||
processTorrentRecord(torrent: IIngestedTorrentAttributes): Promise<void>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ import {ITorrentFileCollection} from "@interfaces/torrent_file_collection";
|
||||
|
||||
export interface ITorrentSubtitleService {
|
||||
assignSubtitles(fileCollection: ITorrentFileCollection): ITorrentFileCollection;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export interface ITrackerService {
|
||||
getTrackers(): Promise<string[]>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +60,4 @@ export class ProcessTorrentsJob implements IProcessTorrentsJob {
|
||||
this.logger.error('Failed to setup channel', error);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ export const cacheConfig = {
|
||||
get MONGO_URI(): string {
|
||||
return `mongodb://${this.MONGODB_USER}:${this.MONGODB_PASSWORD}@${this.MONGODB_HOST}:${this.MONGODB_PORT}/${this.MONGODB_DB}?authSource=admin`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,4 +11,4 @@ export const databaseConfig = {
|
||||
get POSTGRES_URI(): string {
|
||||
return `postgres://${this.POSTGRES_USER}:${this.POSTGRES_PASSWORD}@${this.POSTGRES_HOST}:${this.POSTGRES_PORT}/${this.POSTGRES_DB}`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,4 +3,4 @@ import {BooleanHelpers} from "@helpers/boolean_helpers";
|
||||
export const jobConfig = {
|
||||
JOB_CONCURRENCY: parseInt(process.env.JOB_CONCURRENCY || "1", 10),
|
||||
JOBS_ENABLED: BooleanHelpers.parseBool(process.env.JOBS_ENABLED, true)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,4 +2,4 @@ export const metadataConfig = {
|
||||
IMDB_CONCURRENT: parseInt(process.env.IMDB_CONCURRENT || "1", 10),
|
||||
IMDB_INTERVAL_MS: parseInt(process.env.IMDB_INTERVAL_MS || "1000", 10),
|
||||
TITLE_MATCH_THRESHOLD: Number(process.env.TITLE_MATCH_THRESHOLD || 0.25),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -6,8 +6,8 @@ export const rabbitConfig = {
|
||||
PASSWORD: process.env.RABBITMQ_PASSWORD || 'guest',
|
||||
QUEUE_NAME: process.env.RABBITMQ_QUEUE_NAME || 'ingested',
|
||||
DURABLE: BooleanHelpers.parseBool(process.env.RABBITMQ_DURABLE, true),
|
||||
|
||||
|
||||
get RABBIT_URI(): string {
|
||||
return `amqp://${this.USER}:${this.PASSWORD}@${this.HOST}?heartbeat=30`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const torrentConfig = {
|
||||
MAX_CONNECTIONS_PER_TORRENT: parseInt(process.env.MAX_CONNECTIONS_PER_TORRENT || "20", 10),
|
||||
TIMEOUT: parseInt(process.env.TORRENT_TIMEOUT || "30000", 10)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -3,4 +3,4 @@ import {BooleanHelpers} from "@helpers/boolean_helpers";
|
||||
export const trackerConfig = {
|
||||
TRACKERS_URL: process.env.TRACKERS_URL || 'https://ngosang.github.io/trackerslist/trackers_all.txt',
|
||||
UDP_ENABLED: BooleanHelpers.parseBool(process.env.UDP_TRACKERS_ENABLED, false)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -10,4 +10,4 @@ export interface IImdbEntry extends Document {
|
||||
RuntimeMinutes: string;
|
||||
StartYear: string;
|
||||
TitleType: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ export interface IMongoMetadataQuery {
|
||||
$text: { $search: string },
|
||||
TitleType: string,
|
||||
StartYear?: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface IMongoRepository {
|
||||
connect(): Promise<void>;
|
||||
getImdbId(title: string, category: string, year?: string | number): Promise<string | null>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,4 +15,4 @@ const ImdbEntriesSchema: Schema = new Schema({
|
||||
|
||||
ImdbEntriesSchema.index({ PrimaryTitle: 'text', TitleType: 1, StartYear: 1 }, { background: true });
|
||||
|
||||
export const ImdbEntryModel = mongoose.model<IImdbEntry>('ImdbEntry', ImdbEntriesSchema, 'imdb-entries');
|
||||
export const ImdbEntryModel = mongoose.model<IImdbEntry>('ImdbEntry', ImdbEntriesSchema, 'imdb-entries');
|
||||
|
||||
@@ -20,7 +20,7 @@ const fuseOptions : IFuseOptions<IImdbEntry> = {
|
||||
export class MongoRepository implements IMongoRepository {
|
||||
@inject(IocTypes.ILoggingService) private logger: ILoggingService;
|
||||
private db: typeof mongoose = mongoose;
|
||||
|
||||
|
||||
async connect() : Promise<void> {
|
||||
try {
|
||||
await this.db.connect(configurationService.cacheConfig.MONGO_URI, {directConnection: true});
|
||||
@@ -60,4 +60,4 @@ export class MongoRepository implements IMongoRepository {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,4 +257,4 @@ export class DatabaseRepository implements IDatabaseRepository {
|
||||
|
||||
return newDatabase;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,4 +8,4 @@ export interface IContentAttributes {
|
||||
}
|
||||
|
||||
export interface IContentCreationAttributes extends Optional<IContentAttributes, 'fileIndex' | 'size'> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,4 +61,4 @@ export interface IDatabaseRepository {
|
||||
getSkipTorrent(infoHash: string): Promise<SkipTorrent>;
|
||||
|
||||
createSkipTorrent(torrent: ITorrentCreationAttributes): Promise<[SkipTorrent, boolean | null]>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,4 @@ export interface IFileAttributes extends IParseTorrentTitleResult {
|
||||
}
|
||||
|
||||
export interface IFileCreationAttributes extends Optional<IFileAttributes, 'fileIndex' | 'size' | 'imdbId' | 'imdbSeason' | 'imdbEpisode' | 'kitsuId' | 'kitsuEpisode'> {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ export interface IIngestedPageAttributes {
|
||||
}
|
||||
|
||||
export interface IIngestedPageCreationAttributes extends IIngestedPageAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user