mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Epub Table of Generation fixes for Sigil (#1689)
* Fixed generating table of contents where key lookup could fail with how Sigil packs the epubs. * Tweaked Kavita's fallback ToC generation (when one doesn't exist in the epub) to also use CoalesceKey. * Code smells
This commit is contained in:
parent
fcd9f8f118
commit
ebbaf2d060
@ -213,12 +213,6 @@ public class SettingsController : BaseApiController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setting.Key == ServerSettingKey.EnableSwaggerUi && updateSettingsDto.EnableSwaggerUi + string.Empty != setting.Value)
|
|
||||||
{
|
|
||||||
setting.Value = updateSettingsDto.EnableSwaggerUi + string.Empty;
|
|
||||||
_unitOfWork.SettingsRepository.Update(setting);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setting.Key == ServerSettingKey.TotalBackups && updateSettingsDto.TotalBackups + string.Empty != setting.Value)
|
if (setting.Key == ServerSettingKey.TotalBackups && updateSettingsDto.TotalBackups + string.Empty != setting.Value)
|
||||||
{
|
{
|
||||||
if (updateSettingsDto.TotalBackups > 30 || updateSettingsDto.TotalBackups < 1)
|
if (updateSettingsDto.TotalBackups > 30 || updateSettingsDto.TotalBackups < 1)
|
||||||
|
@ -49,11 +49,6 @@ public class ServerSettingDto
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ConvertBookmarkToWebP { get; set; }
|
public bool ConvertBookmarkToWebP { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If the Swagger UI Should be exposed. Does not require authentication, but does require a JWT.
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("Being removed in v0.7 in favor of dedicated hosted api")]
|
|
||||||
public bool EnableSwaggerUi { get; set; }
|
|
||||||
/// <summary>
|
|
||||||
/// The amount of Backups before cleanup
|
/// The amount of Backups before cleanup
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Value should be between 1 and 30</remarks>
|
/// <remarks>Value should be between 1 and 30</remarks>
|
||||||
|
@ -98,7 +98,6 @@ public static class Seed
|
|||||||
new() {Key = ServerSettingKey.BookmarkDirectory, Value = directoryService.BookmarkDirectory},
|
new() {Key = ServerSettingKey.BookmarkDirectory, Value = directoryService.BookmarkDirectory},
|
||||||
new() {Key = ServerSettingKey.EmailServiceUrl, Value = EmailService.DefaultApiUrl},
|
new() {Key = ServerSettingKey.EmailServiceUrl, Value = EmailService.DefaultApiUrl},
|
||||||
new() {Key = ServerSettingKey.ConvertBookmarkToWebP, Value = "false"},
|
new() {Key = ServerSettingKey.ConvertBookmarkToWebP, Value = "false"},
|
||||||
new() {Key = ServerSettingKey.EnableSwaggerUi, Value = "false"},
|
|
||||||
new() {Key = ServerSettingKey.TotalBackups, Value = "30"},
|
new() {Key = ServerSettingKey.TotalBackups, Value = "30"},
|
||||||
new() {Key = ServerSettingKey.TotalLogs, Value = "30"},
|
new() {Key = ServerSettingKey.TotalLogs, Value = "30"},
|
||||||
new() {Key = ServerSettingKey.EnableFolderWatching, Value = "false"},
|
new() {Key = ServerSettingKey.EnableFolderWatching, Value = "false"},
|
||||||
|
@ -3,6 +3,9 @@ using System.ComponentModel;
|
|||||||
|
|
||||||
namespace API.Entities.Enums;
|
namespace API.Entities.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 15 is blocked as it was EnableSwaggerUi, which is no longer used
|
||||||
|
/// </summary>
|
||||||
public enum ServerSettingKey
|
public enum ServerSettingKey
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -83,12 +86,6 @@ public enum ServerSettingKey
|
|||||||
[Description("ConvertBookmarkToWebP")]
|
[Description("ConvertBookmarkToWebP")]
|
||||||
ConvertBookmarkToWebP = 14,
|
ConvertBookmarkToWebP = 14,
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If the Swagger UI Should be exposed. Does not require authentication, but does require a JWT.
|
|
||||||
/// </summary>
|
|
||||||
[Description("EnableSwaggerUi")]
|
|
||||||
[Obsolete("Being removed in v0.7 in favor of dedicated hosted api")]
|
|
||||||
EnableSwaggerUi = 15,
|
|
||||||
/// <summary>
|
|
||||||
/// Total Number of Backups to maintain before cleaning. Default 30, min 1.
|
/// Total Number of Backups to maintain before cleaning. Default 30, min 1.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Description("TotalBackups")]
|
[Description("TotalBackups")]
|
||||||
|
@ -145,7 +145,6 @@ public class AutoMapperProfiles : Profile
|
|||||||
|
|
||||||
CreateMap<ReadingList, ReadingListDto>();
|
CreateMap<ReadingList, ReadingListDto>();
|
||||||
CreateMap<ReadingListItem, ReadingListItemDto>();
|
CreateMap<ReadingListItem, ReadingListItemDto>();
|
||||||
//.AfterMap((src, dest) => dest.Title = ReadingListHelper.FormatTitle(dest));
|
|
||||||
|
|
||||||
CreateMap<Series, SearchResultDto>()
|
CreateMap<Series, SearchResultDto>()
|
||||||
.ForMember(dest => dest.SeriesId,
|
.ForMember(dest => dest.SeriesId,
|
||||||
|
@ -54,9 +54,6 @@ public class ServerSettingConverter : ITypeConverter<IEnumerable<ServerSetting>,
|
|||||||
case ServerSettingKey.ConvertCoverToWebP:
|
case ServerSettingKey.ConvertCoverToWebP:
|
||||||
destination.ConvertCoverToWebP = bool.Parse(row.Value);
|
destination.ConvertCoverToWebP = bool.Parse(row.Value);
|
||||||
break;
|
break;
|
||||||
case ServerSettingKey.EnableSwaggerUi:
|
|
||||||
destination.EnableSwaggerUi = bool.Parse(row.Value);
|
|
||||||
break;
|
|
||||||
case ServerSettingKey.TotalBackups:
|
case ServerSettingKey.TotalBackups:
|
||||||
destination.TotalBackups = int.Parse(row.Value);
|
destination.TotalBackups = int.Parse(row.Value);
|
||||||
break;
|
break;
|
||||||
|
@ -717,6 +717,20 @@ public class BookService : IBookService
|
|||||||
return PrepareFinalHtml(doc, body);
|
return PrepareFinalHtml(doc, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string CoalesceKey(EpubBookRef book, IDictionary<string, int> mappings, string key)
|
||||||
|
{
|
||||||
|
if (mappings.ContainsKey(CleanContentKeys(key))) return key;
|
||||||
|
|
||||||
|
// Fallback to searching for key (bad epub metadata)
|
||||||
|
var correctedKey = book.Content.Html.Keys.SingleOrDefault(s => s.EndsWith(key));
|
||||||
|
if (!string.IsNullOrEmpty(correctedKey))
|
||||||
|
{
|
||||||
|
key = correctedKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This will return a list of mappings from ID -> page num. ID will be the xhtml key and page num will be the reading order
|
/// This will return a list of mappings from ID -> page num. ID will be the xhtml key and page num will be the reading order
|
||||||
/// this is used to rewrite anchors in the book text so that we always load properly in our reader.
|
/// this is used to rewrite anchors in the book text so that we always load properly in our reader.
|
||||||
@ -743,7 +757,7 @@ public class BookService : IBookService
|
|||||||
|
|
||||||
foreach (var nestedChapter in navigationItem.NestedItems.Where(n => n.Link != null))
|
foreach (var nestedChapter in navigationItem.NestedItems.Where(n => n.Link != null))
|
||||||
{
|
{
|
||||||
var key = BookService.CleanContentKeys(nestedChapter.Link.ContentFileName);
|
var key = CoalesceKey(book, mappings, nestedChapter.Link.ContentFileName);
|
||||||
if (mappings.ContainsKey(key))
|
if (mappings.ContainsKey(key))
|
||||||
{
|
{
|
||||||
nestedChapters.Add(new BookChapterItem()
|
nestedChapters.Add(new BookChapterItem()
|
||||||
@ -760,7 +774,7 @@ public class BookService : IBookService
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (chaptersList.Count != 0) return chaptersList;
|
if (chaptersList.Count != 0) return chaptersList;
|
||||||
// Generate from TOC
|
// Generate from TOC from links (any point past this, Kavita is generating as a TOC doesn't exist)
|
||||||
var tocPage = book.Content.Html.Keys.FirstOrDefault(k => k.ToUpper().Contains("TOC"));
|
var tocPage = book.Content.Html.Keys.FirstOrDefault(k => k.ToUpper().Contains("TOC"));
|
||||||
if (tocPage == null) return chaptersList;
|
if (tocPage == null) return chaptersList;
|
||||||
|
|
||||||
@ -775,16 +789,7 @@ public class BookService : IBookService
|
|||||||
{
|
{
|
||||||
if (!anchor.Attributes.Contains("href")) continue;
|
if (!anchor.Attributes.Contains("href")) continue;
|
||||||
|
|
||||||
var key = BookService.CleanContentKeys(anchor.Attributes["href"].Value).Split("#")[0];
|
var key = CoalesceKey(book, mappings, anchor.Attributes["href"].Value.Split("#")[0]);
|
||||||
if (!mappings.ContainsKey(key))
|
|
||||||
{
|
|
||||||
// Fallback to searching for key (bad epub metadata)
|
|
||||||
var correctedKey = book.Content.Html.Keys.SingleOrDefault(s => s.EndsWith(key));
|
|
||||||
if (!string.IsNullOrEmpty(correctedKey))
|
|
||||||
{
|
|
||||||
key = correctedKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(key) || !mappings.ContainsKey(key)) continue;
|
if (string.IsNullOrEmpty(key) || !mappings.ContainsKey(key)) continue;
|
||||||
var part = string.Empty;
|
var part = string.Empty;
|
||||||
|
@ -90,12 +90,6 @@ public class CacheService : ICacheService
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Caches the files for the given chapter to CacheDirectory
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="chapterId"></param>
|
|
||||||
/// <returns>This will always return the Chapter for the chapterId</returns>
|
|
||||||
public async Task<Chapter> Ensure(int chapterId, bool extractPdfToImages = false)
|
public async Task<Chapter> Ensure(int chapterId, bool extractPdfToImages = false)
|
||||||
{
|
{
|
||||||
_directoryService.ExistOrCreate(_directoryService.CacheDirectory);
|
_directoryService.ExistOrCreate(_directoryService.CacheDirectory);
|
||||||
|
@ -246,21 +246,14 @@ public class Startup
|
|||||||
|
|
||||||
app.UseMiddleware<ExceptionMiddleware>();
|
app.UseMiddleware<ExceptionMiddleware>();
|
||||||
|
|
||||||
Task.Run(async () =>
|
if (env.IsDevelopment())
|
||||||
{
|
|
||||||
var allowSwaggerUi = (await unitOfWork.SettingsRepository.GetSettingsDtoAsync())
|
|
||||||
.EnableSwaggerUi;
|
|
||||||
|
|
||||||
if (env.IsDevelopment() || allowSwaggerUi)
|
|
||||||
{
|
{
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(c =>
|
app.UseSwaggerUI(c =>
|
||||||
{
|
{
|
||||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kavita API " + BuildInfo.Version);
|
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Kavita API " + BuildInfo.Version);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (env.IsDevelopment())
|
if (env.IsDevelopment())
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,6 @@ export interface ServerSettings {
|
|||||||
emailServiceUrl: string;
|
emailServiceUrl: string;
|
||||||
convertBookmarkToWebP: boolean;
|
convertBookmarkToWebP: boolean;
|
||||||
convertCoverToWebP: boolean;
|
convertCoverToWebP: boolean;
|
||||||
enableSwaggerUi: boolean;
|
|
||||||
totalBackups: number;
|
totalBackups: number;
|
||||||
totalLogs: number;
|
totalLogs: number;
|
||||||
enableFolderWatching: boolean;
|
enableFolderWatching: boolean;
|
||||||
|
@ -88,15 +88,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="swagger-ui" class="form-label" aria-describedby="swaggerui-info">Expose Swagger UI</label>
|
|
||||||
<p class="accent" id="swaggerui-info">Allows Swagger UI to be exposed via swagger/ on your server. Authentication is not required, but a valid JWT token is. Requires a restart to take effect. Swagger is hosted on yourip:5000/swagger</p>
|
|
||||||
<div class="form-check form-switch">
|
|
||||||
<input id="swagger-ui" type="checkbox" class="form-check-input" formControlName="enableSwaggerUi" role="switch">
|
|
||||||
<label for="swagger-ui" class="form-check-label">Enable Swagger UI</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- TODO: Move this to Plugins tab once we build out some basic tables -->
|
<!-- TODO: Move this to Plugins tab once we build out some basic tables -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="opds" aria-describedby="opds-info" class="form-label">OPDS</label>
|
<label for="opds" aria-describedby="opds-info" class="form-label">OPDS</label>
|
||||||
|
@ -47,7 +47,6 @@ export class ManageSettingsComponent implements OnInit {
|
|||||||
this.settingsForm.addControl('enableOpds', new FormControl(this.serverSettings.enableOpds, [Validators.required]));
|
this.settingsForm.addControl('enableOpds', new FormControl(this.serverSettings.enableOpds, [Validators.required]));
|
||||||
this.settingsForm.addControl('baseUrl', new FormControl(this.serverSettings.baseUrl, [Validators.required]));
|
this.settingsForm.addControl('baseUrl', new FormControl(this.serverSettings.baseUrl, [Validators.required]));
|
||||||
this.settingsForm.addControl('emailServiceUrl', new FormControl(this.serverSettings.emailServiceUrl, [Validators.required]));
|
this.settingsForm.addControl('emailServiceUrl', new FormControl(this.serverSettings.emailServiceUrl, [Validators.required]));
|
||||||
this.settingsForm.addControl('enableSwaggerUi', new FormControl(this.serverSettings.enableSwaggerUi, [Validators.required]));
|
|
||||||
this.settingsForm.addControl('totalBackups', new FormControl(this.serverSettings.totalBackups, [Validators.required, Validators.min(1), Validators.max(30)]));
|
this.settingsForm.addControl('totalBackups', new FormControl(this.serverSettings.totalBackups, [Validators.required, Validators.min(1), Validators.max(30)]));
|
||||||
this.settingsForm.addControl('totalLogs', new FormControl(this.serverSettings.totalLogs, [Validators.required, Validators.min(1), Validators.max(30)]));
|
this.settingsForm.addControl('totalLogs', new FormControl(this.serverSettings.totalLogs, [Validators.required, Validators.min(1), Validators.max(30)]));
|
||||||
this.settingsForm.addControl('enableFolderWatching', new FormControl(this.serverSettings.enableFolderWatching, [Validators.required]));
|
this.settingsForm.addControl('enableFolderWatching', new FormControl(this.serverSettings.enableFolderWatching, [Validators.required]));
|
||||||
@ -66,7 +65,6 @@ export class ManageSettingsComponent implements OnInit {
|
|||||||
this.settingsForm.get('enableOpds')?.setValue(this.serverSettings.enableOpds);
|
this.settingsForm.get('enableOpds')?.setValue(this.serverSettings.enableOpds);
|
||||||
this.settingsForm.get('baseUrl')?.setValue(this.serverSettings.baseUrl);
|
this.settingsForm.get('baseUrl')?.setValue(this.serverSettings.baseUrl);
|
||||||
this.settingsForm.get('emailServiceUrl')?.setValue(this.serverSettings.emailServiceUrl);
|
this.settingsForm.get('emailServiceUrl')?.setValue(this.serverSettings.emailServiceUrl);
|
||||||
this.settingsForm.get('enableSwaggerUi')?.setValue(this.serverSettings.enableSwaggerUi);
|
|
||||||
this.settingsForm.get('totalBackups')?.setValue(this.serverSettings.totalBackups);
|
this.settingsForm.get('totalBackups')?.setValue(this.serverSettings.totalBackups);
|
||||||
this.settingsForm.get('totalLogs')?.setValue(this.serverSettings.totalLogs);
|
this.settingsForm.get('totalLogs')?.setValue(this.serverSettings.totalLogs);
|
||||||
this.settingsForm.get('enableFolderWatching')?.setValue(this.serverSettings.enableFolderWatching);
|
this.settingsForm.get('enableFolderWatching')?.setValue(this.serverSettings.enableFolderWatching);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"name": "GPL-3.0",
|
"name": "GPL-3.0",
|
||||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||||
},
|
},
|
||||||
"version": "0.6.1.8"
|
"version": "0.6.1.9"
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
@ -12843,11 +12843,6 @@
|
|||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "If the server should save bookmarks as WebP encoding"
|
"description": "If the server should save bookmarks as WebP encoding"
|
||||||
},
|
},
|
||||||
"enableSwaggerUi": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "If the Swagger UI Should be exposed. Does not require authentication, but does require a JWT.",
|
|
||||||
"deprecated": true
|
|
||||||
},
|
|
||||||
"totalBackups": {
|
"totalBackups": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "The amount of Backups before cleanup",
|
"description": "The amount of Backups before cleanup",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user