using Bugsnag; using Bugsnag.Payload; using Dapper; using ErsatzTV.Core; using ErsatzTV.Core.Emby; using ErsatzTV.Core.FFmpeg; using ErsatzTV.Core.Interfaces.Emby; using ErsatzTV.Core.Interfaces.FFmpeg; using ErsatzTV.Core.Interfaces.Images; using ErsatzTV.Core.Interfaces.Jellyfin; using ErsatzTV.Core.Interfaces.Metadata; using ErsatzTV.Core.Interfaces.Plex; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Repositories.Caching; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Jellyfin; using ErsatzTV.Core.Metadata; using ErsatzTV.Core.Plex; using ErsatzTV.FFmpeg.Runtime; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Data.Repositories; using ErsatzTV.Infrastructure.Data.Repositories.Caching; using ErsatzTV.Infrastructure.Emby; using ErsatzTV.Infrastructure.Images; using ErsatzTV.Infrastructure.Jellyfin; using ErsatzTV.Infrastructure.Metadata; using ErsatzTV.Infrastructure.Plex; using ErsatzTV.Infrastructure.Runtime; using ErsatzTV.Infrastructure.Search; using ErsatzTV.Infrastructure.Sqlite.Data; using ErsatzTV.Scanner.Core.Emby; using ErsatzTV.Scanner.Core.FFmpeg; using ErsatzTV.Scanner.Core.Interfaces.FFmpeg; using ErsatzTV.Scanner.Core.Interfaces.Metadata; using ErsatzTV.Scanner.Core.Interfaces.Metadata.Nfo; using ErsatzTV.Scanner.Core.Jellyfin; using ErsatzTV.Scanner.Core.Metadata; using ErsatzTV.Scanner.Core.Metadata.Nfo; using ErsatzTV.Scanner.Core.Plex; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.IO; using Serilog; using Serilog.Events; using Serilog.Formatting.Compact; using Exception = System.Exception; using IConfiguration = Bugsnag.IConfiguration; namespace ErsatzTV.Scanner; public class Program { public static async Task Main(string[] args) { Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Error) .Enrich.FromLogContext() .WriteTo.Console(new CompactJsonFormatter(), standardErrorFromLevel: LogEventLevel.Debug) .CreateLogger(); try { await CreateHostBuilder(args).Build().RunAsync(); return 0; } catch (Exception ex) { Log.Fatal(ex, "ErsatzTV.Scanner host terminated unexpectedly"); return 1; } finally { await Log.CloseAndFlushAsync(); } } private static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices( (context, services) => { string databaseProvider = context.Configuration.GetValue("provider", Provider.Sqlite.Name) ?? string.Empty; var sqliteConnectionString = $"Data Source={FileSystemLayout.DatabasePath};foreign keys=true;"; string mySqlConnectionString = context.Configuration.GetValue("MySql:ConnectionString") ?? string.Empty; services.AddDbContext( options => { if (databaseProvider == Provider.Sqlite.Name) { options.UseSqlite( sqliteConnectionString, o => { o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); o.MigrationsAssembly("ErsatzTV.Infrastructure.Sqlite"); }); } if (databaseProvider == Provider.MySql.Name) { options.UseMySql( mySqlConnectionString, ServerVersion.AutoDetect(mySqlConnectionString), o => { o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); o.MigrationsAssembly("ErsatzTV.Infrastructure.MySql"); } ); } }, ServiceLifetime.Scoped, ServiceLifetime.Singleton); services.AddDbContextFactory( options => { if (databaseProvider == Provider.Sqlite.Name) { options.UseSqlite( sqliteConnectionString, o => { o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); o.MigrationsAssembly("ErsatzTV.Infrastructure.Sqlite"); }); } if (databaseProvider == Provider.MySql.Name) { options.UseMySql( mySqlConnectionString, ServerVersion.AutoDetect(mySqlConnectionString), o => { o.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); o.MigrationsAssembly("ErsatzTV.Infrastructure.MySql"); } ); } }); if (databaseProvider == Provider.Sqlite.Name) { TvContext.LastInsertedRowId = "last_insert_rowid()"; TvContext.CaseInsensitiveCollation = "NOCASE"; SqlMapper.AddTypeHandler(new DateTimeOffsetHandler()); SqlMapper.AddTypeHandler(new GuidHandler()); SqlMapper.AddTypeHandler(new TimeSpanHandler()); } if (databaseProvider == Provider.MySql.Name) { TvContext.LastInsertedRowId = "last_insert_id()"; TvContext.CaseInsensitiveCollation = "utf8mb4_general_ci"; } services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); // TODO: real bugsnag? services.AddSingleton(_ => new BugsnagNoopClient()); services.AddMediatR(config => config.RegisterServicesFromAssemblyContaining()); services.AddMemoryCache(); services.AddHostedService(); }) .UseSerilog(); private class BugsnagNoopClient : IClient { public void Notify(Exception exception) { } public void Notify(Exception exception, Middleware callback) { } public void Notify(Exception exception, Severity severity) { } public void Notify(Exception exception, Severity severity, Middleware callback) { } public void Notify(Exception exception, HandledState handledState) { } public void Notify(Exception exception, HandledState handledState, Middleware callback) { } public void Notify(Report report, Middleware callback) { } public void BeforeNotify(Middleware middleware) { } public IBreadcrumbs Breadcrumbs => new Breadcrumbs(Configuration); public ISessionTracker SessionTracking => new SessionTracker(Configuration); public IConfiguration Configuration => new Configuration(); } }