Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Feat/#8 #48

Closed
wants to merge 8 commits into from
Closed
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
8 changes: 8 additions & 0 deletions Epub/KoeBook.Epub/Contracts/Services/IEpubGeneration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using KoeBook.Epub.Models;

namespace KoeBook.Epub.Contracts.Services;

public interface IEpubGeneration
{
ValueTask<bool> TryCreateEpubAsync(EpubDocument epubDocument, string tmpDirectory, CancellationToken ct);
}
6 changes: 6 additions & 0 deletions Epub/KoeBook.Epub/Contracts/Services/IFileExtensionService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace KoeBook.Epub.Contracts.Services;

public interface IFileExtensionService
{
public string GetImagesMediaType(string fileName);
}
11 changes: 11 additions & 0 deletions Epub/KoeBook.Epub/Contracts/Services/IScraperSelectorService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using KoeBook.Epub.Models;

namespace KoeBook.Epub.Contracts.Services;

/// <summary>
/// スクレイピングを行い、EpubDocumentを作成します。
/// </summary>
public interface IScraperSelectorService
{
public ValueTask<EpubDocument> ScrapingAsync(string url, string coverFillePath, string tempDirectory, Guid id, CancellationToken ct);
}
8 changes: 8 additions & 0 deletions Epub/KoeBook.Epub/Contracts/Services/IScrapingService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using KoeBook.Epub.Models;

namespace KoeBook.Epub.Contracts.Services;

public interface IScrapingService : IScraperSelectorService
{
public bool IsMatchSite(Uri url);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using NAudio.Wave;
using NAudio.Wave;

namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public sealed class Audio
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public class Chapter
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public record CssClass(string Name, string Text);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public abstract class Element
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,11 @@
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Globalization;
using System.IO.Compression;
using System.Text;
using System.Xml;
using NAudio.Mixer;

namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public class EpubDocument(string title, string author, string coverFilePath, Guid id)
{
readonly string _containerXml = """
<?xml version="1.0" encoding="UTF-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="OEBPS/book.opf" media-type="application/oebps-package+xml" />
</rootfiles>
</container>
""";

public string Title { get; set; } = title;
public string Author { get; set; } = author;

Expand All @@ -41,6 +28,33 @@ public class EpubDocument(string title, string author, string coverFilePath, Gui
];
public List<Chapter> Chapters { get; set; } = [];

internal void EnsureChapter()
{
if (Chapters.Count == 0)
Chapters.Add(new Chapter() { Title = null });
}

internal void EnsureSection(int chapterIndex)
{
EnsureChapter();

if (Chapters[chapterIndex].Sections.Count == 0)
{
if (Chapters[chapterIndex].Title != null)
Chapters[chapterIndex].Sections.Add(new Section(Chapters[chapterIndex].Title!));
else
Chapters[chapterIndex].Sections.Add(new Section(Title));
}
}

internal void EnsureParagraph(int chapterIndex, int sectionIndex)
{
EnsureSection(chapterIndex);

if (Chapters[chapterIndex].Sections[sectionIndex].Elements.Count == 0)
Chapters[chapterIndex].Sections[sectionIndex].Elements.Add(new Paragraph());
}

public string CreateNavXhtml()
{
var builder = new StringBuilder($"""
Expand All @@ -57,7 +71,7 @@ public string CreateNavXhtml()
""");
if (Chapters.Count == 1 && Chapters[0].Title == null)
{
for (int i = 0; i < Chapters[0].Sections.Count; i++)
for (var i = 0; i < Chapters[0].Sections.Count; i++)
{
builder.AppendLine($"""
<li>
Expand All @@ -68,14 +82,14 @@ public string CreateNavXhtml()
}
else
{
for (int i = 0; i < Chapters.Count; i++)
for (var i = 0; i < Chapters.Count; i++)
{
builder.AppendLine($"""
<li>
<span>{Chapters[i].Title}</span>
<ol>
""");
for (int j = 0; j < Chapters[i].Sections.Count; j++)
for (var j = 0; j < Chapters[i].Sections.Count; j++)
{
builder.AppendLine($"""
<li>
Expand Down Expand Up @@ -126,9 +140,9 @@ public string CreateOpf()
""");

var totalTime = TimeSpan.Zero;
for (int i = 0; i < Chapters.Count; i++)
for (var i = 0; i < Chapters.Count; i++)
{
for (int j = 0; j < Chapters[i].Sections.Count; j++)
for (var j = 0; j < Chapters[i].Sections.Count; j++)
{
var time = Chapters[i].Sections[j].GetTotalTime();
totalTime += time;
Expand All @@ -146,9 +160,9 @@ public string CreateOpf()
<item id="nav" href="nav.xhtml" properties="nav" media-type="application/xhtml+xml" />
""");

for (int i = 0; i < Chapters.Count; i++)
for (var i = 0; i < Chapters.Count; i++)
{
for (int j = 0; j < Chapters[i].Sections.Count; j++)
for (var j = 0; j < Chapters[i].Sections.Count; j++)
{
builder.AppendLine($"""
<item id="section_{i}_{j}" href="{Chapters[i].Sections[j].Id}.xhtml" media-type="application/xhtml+xml" media-overlay="smil_{i}_{j}" />
Expand All @@ -174,9 +188,9 @@ public string CreateOpf()
<spine page-progression-direction="ltr">
""");

for (int i = 0; i < Chapters.Count; i++)
for (var i = 0; i < Chapters.Count; i++)
{
for (int j = 0; j < Chapters[i].Sections.Count; j++)
for (var j = 0; j < Chapters[i].Sections.Count; j++)
{
builder.AppendLine($"""
<itemref idref="section_{i}_{j}" id="itemref_{i}_{j}" />
Expand All @@ -191,97 +205,12 @@ public string CreateOpf()
return builder.ToString();
}

public async Task<bool> TryCreateEpubAsync(string tmpDirectory, string name, CancellationToken ct)
{
if (!File.Exists(CoverFilePath))
{
throw new FileNotFoundException("指定されたカバーファイルが存在しません", CoverFilePath);
}
try
{
using var fs = File.Create(Path.Combine(tmpDirectory, $"{name}.epub"));
using var archive = new ZipArchive(fs, ZipArchiveMode.Create);

var mimeTypeEntry = archive.CreateEntry("mimetype", CompressionLevel.NoCompression);
using (var mimeTypeStream = new StreamWriter(mimeTypeEntry.Open()))
{
await mimeTypeStream.WriteAsync("application/epub+zip").ConfigureAwait(false);
await mimeTypeStream.FlushAsync(ct).ConfigureAwait(false);
}

var containerEntry = archive.CreateEntry("META-INF/container.xml");
using (var containerStream = new StreamWriter(containerEntry.Open()))
{
await containerStream.WriteLineAsync(_containerXml).ConfigureAwait(false);
await containerStream.FlushAsync(ct).ConfigureAwait(false);
}

archive.CreateEntryFromFile(CoverFilePath, $"OEBPS/{Path.GetFileName(CoverFilePath)}");

var cssEntry = archive.CreateEntry("OEBPS/style.css");
using (var cssStream = new StreamWriter(cssEntry.Open()))
{
await cssStream.WriteLineAsync(CreateCssText()).ConfigureAwait(false);
await cssStream.FlushAsync(ct).ConfigureAwait(false);
}

var navEntry = archive.CreateEntry("OEBPS/nav.xhtml");
using (var navStream = new StreamWriter(navEntry.Open()))
{
await navStream.WriteLineAsync(CreateNavXhtml()).ConfigureAwait(false);
await navStream.FlushAsync(ct).ConfigureAwait(false);
}

var opfEntry = archive.CreateEntry("OEBPS/book.opf");
using (var opfStream = new StreamWriter(opfEntry.Open()))
{
await opfStream.WriteLineAsync(CreateOpf()).ConfigureAwait(false);
await opfStream.FlushAsync(ct).ConfigureAwait(false);
}

for (int i = 0; i < Chapters.Count; i++)
{
for (int j = 0; j < Chapters[i].Sections.Count; j++)
{
var sectionXhtmlEntry = archive.CreateEntry($"OEBPS/{Chapters[i].Sections[j].Id}.xhtml");
using (var sectionXhtmlStream = new StreamWriter(sectionXhtmlEntry.Open()))
{
await sectionXhtmlStream.WriteLineAsync(Chapters[i].Sections[j].CreateSectionXhtml()).ConfigureAwait(false);
await sectionXhtmlStream.FlushAsync(ct).ConfigureAwait(false);
}
var sectionSmilEntry = archive.CreateEntry($"OEBPS/{Chapters[i].Sections[j].Id}_audio.smil");
using (var sectionSmilStream = new StreamWriter(sectionSmilEntry.Open()))
{
await sectionSmilStream.WriteLineAsync(Chapters[i].Sections[j].CreateSectionSmil()).ConfigureAwait(false);
await sectionSmilStream.FlushAsync(ct).ConfigureAwait(false);
}
for (var k = 0; k < Chapters[i].Sections[j].Elements.Count; k++)
{
var element = Chapters[i].Sections[j].Elements[k];
if (element is Paragraph para && para.Audio != null)
{
var audioEntry = archive.CreateEntry($"OEBPS/{Chapters[i].Sections[j].Id}_p{k}.mp3");
using var audioStream = para.Audio.GetStream();
using var audioEntryStream = audioEntry.Open();
await audioStream.CopyToAsync(audioEntryStream, ct).ConfigureAwait(false);
await audioEntryStream.FlushAsync(ct).ConfigureAwait(false);
}
else if (element is Picture pic && File.Exists(pic.PictureFilePath))
{
archive.CreateEntryFromFile(pic.PictureFilePath, $"OEBPS/{Chapters[i].Sections[j].Id}_p{k}{Path.GetExtension(pic.PictureFilePath)}");
}
}
}
}
return true;
}
catch (OperationCanceledException)
{
throw;
}
catch
{
return false;
}
}
public string CreateContainerXml() => """
<?xml version="1.0" encoding="UTF-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
<rootfiles>
<rootfile full-path="OEBPS/book.opf" media-type="application/oebps-package+xml" />
</rootfiles>
</container>
""";
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public sealed class Paragraph : Element
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public class Picture(string path) : Element
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text;

namespace KoeBook.Epub;
namespace KoeBook.Epub.Models;

public sealed class Section(string title)
{
Expand All @@ -20,7 +20,7 @@ public string CreateSectionXhtml()
<body>
""");

for (int i = 0; i < Elements.Count; i++)
for (var i = 0; i < Elements.Count; i++)
{
if (Elements[i] is Paragraph para)
{
Expand Down Expand Up @@ -55,7 +55,7 @@ public string CreateSectionSmil()
<body>
""");

for (int i = 0; i < Elements.Count; i++)
for (var i = 0; i < Elements.Count; i++)
{
if (Elements[i] is Paragraph para && para.Audio != null)
{
Expand Down
Loading
Loading