feat: 支持长篇小说分层架构(卷/弧/章三级结构)

This commit is contained in:
voocel
2026-03-12 16:27:15 +08:00
parent 3d65afa276
commit bce0adeff1
19 changed files with 1045 additions and 16 deletions

View File

@@ -44,3 +44,93 @@ func (s *Store) LoadRecentSummaries(current, count int) ([]domain.ChapterSummary
func (s *Store) LoadAllSummaries(current int) ([]domain.ChapterSummary, error) {
return s.LoadRecentSummaries(current, current)
}
// SaveArcSummary 保存弧级摘要到 summaries/arc-v{vol}a{arc}.json。
func (s *Store) SaveArcSummary(sum domain.ArcSummary) error {
return s.writeJSON(fmt.Sprintf("summaries/arc-v%02da%02d.json", sum.Volume, sum.Arc), sum)
}
// LoadArcSummary 读取指定弧的摘要。
func (s *Store) LoadArcSummary(volume, arc int) (*domain.ArcSummary, error) {
var sum domain.ArcSummary
if err := s.readJSON(fmt.Sprintf("summaries/arc-v%02da%02d.json", volume, arc), &sum); err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
return &sum, nil
}
// LoadArcSummaries 加载一卷内所有已有弧摘要。
// 从分层大纲获取实际弧数,无分层大纲时扫描到首个缺失为止。
func (s *Store) LoadArcSummaries(volume int) ([]domain.ArcSummary, error) {
maxArc := s.arcCountForVolume(volume)
var result []domain.ArcSummary
for arc := 1; arc <= maxArc; arc++ {
sum, err := s.LoadArcSummary(volume, arc)
if err != nil {
return nil, err
}
if sum != nil {
result = append(result, *sum)
}
}
return result, nil
}
// SaveVolumeSummary 保存卷级摘要到 summaries/vol-v{vol}.json。
func (s *Store) SaveVolumeSummary(sum domain.VolumeSummary) error {
return s.writeJSON(fmt.Sprintf("summaries/vol-v%02d.json", sum.Volume), sum)
}
// LoadVolumeSummary 读取指定卷的摘要。
func (s *Store) LoadVolumeSummary(volume int) (*domain.VolumeSummary, error) {
var sum domain.VolumeSummary
if err := s.readJSON(fmt.Sprintf("summaries/vol-v%02d.json", volume), &sum); err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
return &sum, nil
}
// LoadAllVolumeSummaries 加载所有已有卷摘要。
// 从分层大纲获取实际卷数,无分层大纲时扫描到首个缺失为止。
func (s *Store) LoadAllVolumeSummaries() ([]domain.VolumeSummary, error) {
maxVol := s.volumeCount()
var result []domain.VolumeSummary
for vol := 1; vol <= maxVol; vol++ {
sum, err := s.LoadVolumeSummary(vol)
if err != nil {
return nil, err
}
if sum != nil {
result = append(result, *sum)
}
}
return result, nil
}
// volumeCount 从分层大纲获取卷数,无大纲时返回安全上限。
func (s *Store) volumeCount() int {
volumes, err := s.LoadLayeredOutline()
if err == nil && len(volumes) > 0 {
return len(volumes)
}
return 20
}
// arcCountForVolume 从分层大纲获取指定卷的弧数,无大纲时返回安全上限。
func (s *Store) arcCountForVolume(volume int) int {
volumes, err := s.LoadLayeredOutline()
if err == nil {
for _, v := range volumes {
if v.Index == volume {
return len(v.Arcs)
}
}
}
return 20
}