ficdown/Ficdown.Parser/Render/EpubRenderer.cs

147 lines
4.8 KiB
C#

namespace Ficdown.Parser.Render
{
using System;
using System.Text;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Epub4Net;
using Ionic.Zip;
using Ionic.Zlib;
#region fix for bug in epub4net
// https://bitbucket.org/dalager/epub4net/issues/2/windows-path-separator-hard-coded-in
public class FixedFileSystemManager : IFileSystemManager
{
private FileSystemManager _fsm;
public FixedFileSystemManager()
{
_fsm = new FileSystemManager(Guid.NewGuid().ToString());
}
public void SetupOutputDir()
{
_fsm.SetupOutputDir();
}
public string ContentDir
{
get { return _fsm.ContentDir; }
set { _fsm.ContentDir = value; }
}
public string BuildDirectory
{
get { return _fsm.BuildDirectory; }
set { _fsm.BuildDirectory = value; }
}
public void CreateTocFile(Epub epub)
{
_fsm.CreateTocFile(epub);
}
public void CreateContentOpfFile(Epub epub)
{
_fsm.CreateContentOpfFile(epub);
}
public void CopyChapterFilesToContentFolder(Epub epub)
{
_fsm.CopyChapterFilesToContentFolder(epub);
}
public string ZipEpub(Epub epub)
{
var epubFilename = epub.Title + ".epub";
if(File.Exists(epubFilename)) File.Delete(epubFilename);
using(var zip = new ZipFile(epubFilename, Encoding.UTF8))
{
zip.EmitTimesInWindowsFormatWhenSaving = false;
zip.CompressionLevel = CompressionLevel.None;
zip.AddFile(Path.Combine(_fsm.BuildDirectory, "mimetype"), "\\");
zip.Save();
File.Delete(Path.Combine(_fsm.BuildDirectory, "mimetype"));
zip.AddDirectory(_fsm.BuildDirectory);
zip.Save();
}
return epubFilename;
}
public void CopyResourceFilesToContentFolder(Epub epub)
{
_fsm.CopyResourceFilesToContentFolder(epub);
}
public void ValidatePathsExists(IEnumerable<IPathed> fileList)
{
_fsm.ValidatePathsExists(fileList);
}
public void DeleteBuildDir()
{
_fsm.DeleteBuildDir();
}
}
#endregion
public class EpubRenderer : HtmlRenderer
{
private static readonly Logger _logger = Logger.GetLogger<EpubRenderer>();
private readonly string _author;
private readonly string _bookId;
private readonly string _language;
public EpubRenderer(string author, string bookId, string language) : base(language)
{
_author = author;
_bookId = bookId ?? Guid.NewGuid().ToString("D");
_language = language ?? "en";
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
}
public override void Render(Model.Parser.ResolvedStory story, string outPath, bool debug = false)
{
_logger.Debug("Generating epub...");
var temppath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
Directory.CreateDirectory(temppath);
base.Render(story, temppath, debug);
var chapters = new List<Chapter>
{
new Chapter(Path.Combine(temppath, "index.html"), "index.html", "Title Page")
};
chapters.AddRange(from file in Directory.GetFiles(temppath)
select Path.GetFileName(file)
into fname
where fname != "index.html" && fname != "styles.css"
select new Chapter(Path.Combine(temppath, fname), fname, fname.Replace(".html", string.Empty)));
var epub = new Epub(Story.Name, _author, chapters);
epub.BookId = _bookId;
epub.Language = _language;
epub.AddResourceFile(new ResourceFile("styles.css", Path.Combine(temppath, "styles.css"), "text/css"));
if (!string.IsNullOrWhiteSpace(ImageDir))
{
var dirname = ImageDir.Substring(ImageDir.LastIndexOf(Path.DirectorySeparatorChar) + 1);
var tempimgdir = Path.Combine(temppath, dirname);
foreach (var img in Directory.GetFiles(tempimgdir))
{
var fname = Path.GetFileName(img);
epub.AddResourceFile(new ResourceFile(fname,
Path.Combine(tempimgdir, fname), MimeHelper.GetMimeType(img)));
}
}
var builder = new EPubBuilder(new FixedFileSystemManager(), Guid.NewGuid().ToString());
var built = builder.Build(epub);
File.Move(built, outPath);
Directory.Delete(temppath, true);
}
}
}