返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Go

On the Last Day of 2025, Sharing the Ebook Conversion Tool Website I Built with Go

Fed up with conversion tools plastered with ads, I casually wrapped a CLI tool in a Go-Gin shell. I just wanted some peace and quiet, but these people crashed my server outright, so I've been forced to take it down for now. The code is dumped on GitHub—don't expect me to go fix that unfinished login feature.

曦远 (DealiAxy)约 15 分钟
目录7 个章节

Preface

A web-based novel conversion tool that supports converting txt files to ebook formats such as epub, mobi, and azw3

I actually built this project in August this year and never shared it.

When I was looking for a tool to convert txt ebooks to EPUB, a lot of them had ads. I found a Go CLI tool on GitHub: kaf-cli. It worked pretty well, but having to type commands every time was a bit of a hassle, so I turned it into a website with go-gin to make it more convenient.

I posted it in a reading group, and quite a few people have been using it.

But recently this website has overwhelmed my server, so I've been forced to take it down.

This post is a brief share of the website, as a wrap-up for 2025~

This project also spawned an internationalization feature implemented with Alpine.js.


This project is forked from ystyle/kaf-cli. On top of keeping the original CLI functionality, it adds a visual web interface for a more convenient experience.

Project URL: https://github.com/Deali-Axy/ebook-generator

Main Features

🌐 Web Features

  • 📁 File upload: Supports txt file uploads, up to 50MB
  • 🔄 Format conversion: Supports converting to epub, mobi, and azw3 formats
  • 📊 Real-time progress: View conversion progress in real time via SSE
  • 📥 File download: Download the ebook file after conversion completes
  • 🗑️ Auto cleanup: Supports manually cleaning up temporary files
  • 📖 API docs: Integrated Swagger UI for easy debugging
  • 🎨 Visual interface: A simple, easy-to-use HTML interface

📚 Conversion Features

  • Automatically detect book title and chapters
  • Automatically detect character encoding (fixes Chinese garbled text)
  • Custom chapter title detection rules
  • Custom volume title detection rules
  • Automatically generate bold, centered titles for chapter bodies
  • Automatic paragraph detection and indentation
  • Support for generating Orly-style book covers
  • Automatically extract title and author from Zhixuan Cangshu-format filenames
  • Ultra-fast conversion (epub generation at 300+ chapters/s)

Screenshots

Home page

Conversion progress and download

Web code

I'll just paste some of the code. I actually also built login and registration, but there were bugs, so I didn't wire them up on the frontend~

// main 启动Web服务
func main() {
	// 设置Gin模式
	if os.Getenv("GIN_MODE") == "" {
		gin.SetMode(gin.DebugMode)
	}

	// 初始化服务管理器
	serviceManager, err := initServiceManager()
	if err != nil {
		log.Fatal("初始化服务管理器失败:", err)
	}

	// 启动所有服务
	if err := serviceManager.Start(); err != nil {
		log.Fatal("启动服务失败:", err)
	}

	// 设置优雅关闭
	defer func() {
		if err := serviceManager.Stop(); err != nil {
			log.Printf("停止服务时出错: %v", err)
		}
	}()

	// 初始化Web服务相关组件
	initWebServices(serviceManager)

	// 创建Gin引擎
	r := gin.Default()

	// 初始化SEO服务
	seoService := initSEOService()

	// 添加中间件
	r.Use(middleware.CORS())
	r.Use(middleware.Logger())
	r.Use(middleware.Recovery())
	r.Use(middleware.AddSecurityHeaders())
	r.Use(middleware.AddCacheHeaders())
	r.Use(middleware.SEOMiddleware(seoService))

	// 设置文件上传大小限制 (50MB)
	r.MaxMultipartMemory = 50 << 20

	// API路由组
	api := r.Group("/api")
	{
		// 基础转换功能
		api.POST("/upload", handlers.UploadFile)
		api.POST("/convert", handlers.ConvertBook)
		api.GET("/status/:taskId", handlers.GetTaskStatus)
		api.GET("/download/:fileId", handlers.DownloadFile)
		api.DELETE("/cleanup/:taskId", handlers.CleanupTask)
		api.GET("/events/:taskId", handlers.GetTaskEvents)

		// 用户认证相关路由
		auth := api.Group("/auth")
		{
			auth.POST("/register", handlers.Register)
			auth.POST("/login", handlers.Login)
			auth.GET("/profile", handlers.AuthMiddleware(), handlers.GetProfile)
			auth.PUT("/profile", handlers.AuthMiddleware(), handlers.UpdateProfile)
			auth.POST("/logout", handlers.AuthMiddleware(), handlers.Logout)
			auth.POST("/refresh", handlers.AuthMiddleware(), handlers.RefreshToken)
			auth.PUT("/password", handlers.AuthMiddleware(), handlers.ChangePassword)
		}

		// 转换历史相关路由(需要认证)
		history := api.Group("/history")
		history.Use(handlers.AuthMiddleware())
		{
			history.GET("", handlers.GetHistories)
			history.GET("/stats", handlers.GetHistoryStats)
			history.DELETE("/:id", handlers.DeleteHistory)
		}

		// 转换预设相关路由(需要认证)
		presets := api.Group("/presets")
		presets.Use(handlers.AuthMiddleware())
		{
			presets.POST("", handlers.CreatePreset)
			presets.GET("", handlers.GetPresets)
			presets.GET("/:id", handlers.GetPreset)
			presets.PUT("/:id", handlers.UpdatePreset)
			presets.DELETE("/:id", handlers.DeletePreset)
		}

		// 批量转换相关路由(需要认证)
		batch := api.Group("/batch")
		batch.Use(handlers.AuthMiddleware())
		{
			batch.POST("/convert", handlers.BatchConvert)
		}
	}

	// 集成Swagger文档
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// 静态文件服务
	r.Static("/static", "./web/static")
	r.StaticFile("/", "./web/static/index.html")
	r.StaticFile("/demo", "./web/static/index.html")

	// SEO相关文件 - 动态生成
	r.GET("/sitemap.xml", handlers.GenerateSitemap)
	r.GET("/robots.txt", handlers.GenerateRobotsTxt)

	// SEO状态监控
	seo := r.Group("/seo")
	{
		seo.GET("/status", handlers.GetSEOStatus)
	}

	// 健康检查接口
	r.GET("/health", func(c *gin.Context) {
		c.JSON(200, gin.H{"status": "ok"})
	})

	// 启动服务
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	log.Printf("服务启动在端口: %s", port)
	log.Printf("Swagger文档地址: http://localhost:%s/swagger/index.html", port)

	if err := r.Run(":" + port); err != nil {
		log.Fatal("启动服务失败:", err)
	}
}

Wrap-up

That's all for now. It's getting late—happy New Year everyone~

_EOF_

On the Last Day of 2025, Sharing the Ebook Conversion Tool Website I Built with Go

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…