story(vol05): 完成89至112章与第五卷阅读包
This commit is contained in:
+2
-2
@@ -8,7 +8,7 @@
|
||||
./tools/validate-project.ps1
|
||||
```
|
||||
|
||||
检查相对链接、年表、年龄、粮食算术、正文00—68起的连续章号、三卷范围与第三卷章纲、当前EP01 V05的25场/1290秒预算等;允许在68章之后继续续写。脚本保留UTF-8 BOM,兼容Windows PowerShell读取中文。历史75秒技术试片单独校验,不混用当前第一集场号;通过不等于艺术质量、真实片长或配音验收通过。
|
||||
检查相对链接、年表、年龄、粮食算术、独立序章00起的连续章号、前五卷范围及章纲、当前EP01 V05的25场/1290秒预算等;支持三位及更多位章号,后续续写不按两位截断。脚本保留UTF-8 BOM,兼容Windows PowerShell读取中文。历史75秒技术试片单独校验,不混用当前第一集场号;通过不等于艺术质量、真实片长或配音验收通过。
|
||||
|
||||
## 阅读合订本与台词同步
|
||||
|
||||
@@ -18,7 +18,7 @@ python tools/build-reading-editions.py --date 2026-10-30
|
||||
|
||||
从逐章稿生成前三卷68章合订本、第三卷20章完整阅读本,保留前30章节选、前48章合订本和第二卷24章阅读本的原范围;从现行12集阅读稿生成动画合订本。同步EP02—12逐集与总录制表,并核对Fountain和阅读稿的台词顺序与内容。保留已有录制状态、配音身份、选定take、实测时长和旧台词ID;新ID从源稿读取。修订应先改源稿,合订本可重建。
|
||||
|
||||
第四卷已有69—88章时,默认流程也汇集前四卷88章与第四卷独立阅读本。只续写小说时运行`python tools/build-reading-editions.py --date 2026-10-31 --novel-only`,仅生成这两份新范围阅读本,保留旧范围版本,并跳过所有影像剧本、录制表与声音资料的写入。
|
||||
第四卷已有69—88章时,默认流程也汇集前四卷88章与第四卷独立阅读本;第五卷89—112章完整时增加前五卷与第五卷阅读本。只续写小说时运行`python tools/build-reading-editions.py --date 2026-11-01 --novel-only`,按当前完整范围仅生成前五卷112章与第五卷两份阅读本(尚无第五卷时仍用四卷范围),保留此前范围与日期,跳过所有影像剧本、录制表与声音资料的写入。第五卷按数值排序章号,不按文件名字符串排列100与99。
|
||||
|
||||
## 图片素材站导出
|
||||
|
||||
|
||||
@@ -224,6 +224,8 @@ def build_novel_edition(chapters, destination, title, scope, edition_date):
|
||||
parts.append('# 第三卷 无神罚的异端')
|
||||
elif path.name.startswith('69_'):
|
||||
parts.append('# 第四卷 无证人的长路')
|
||||
elif path.name.startswith('89_'):
|
||||
parts.append('# 第五卷 越过边境')
|
||||
parts.append(re.sub(r'^(#+) ', r'\1# ', source, flags=re.M).rstrip())
|
||||
write(destination, '\n\n'.join(parts) + '\n')
|
||||
return count
|
||||
@@ -250,16 +252,43 @@ def build_four_volume_editions(edition_date):
|
||||
print(fourth_out)
|
||||
|
||||
|
||||
def build_five_volume_editions(edition_date):
|
||||
"""汇集五卷当前范围,历史阅读本保持原来的范围与日期。"""
|
||||
chapters = []
|
||||
for volume in ('第一卷', '第二卷', '第三卷', '第四卷', '第五卷'):
|
||||
paths = (NOVEL / '03_正文' / volume).glob('*.md')
|
||||
chapters.extend(sorted((p for p in paths if re.match(r'^\d+_', p.name)),
|
||||
key=lambda p: int(p.name.split('_', 1)[0])))
|
||||
numbers = [int(p.name.split('_', 1)[0]) for p in chapters]
|
||||
if numbers != list(range(113)):
|
||||
raise ValueError('五卷应为序章00和正文01—112,无缺号或重复')
|
||||
fifth = [p for p in chapters if 89 <= int(p.name.split('_', 1)[0]) <= 112]
|
||||
combined = NOVEL / '前112章_阅读合订本.md'
|
||||
fifth_out = NOVEL / '第五卷_越过边境_阅读合订本.md'
|
||||
full_count = build_novel_edition(chapters, combined,
|
||||
'《寂静诸神:炉火》前五卷阅读合订本',
|
||||
'独立序章+正文1—112章;第一、二、五卷各24章,第三、四卷各20章完整初稿', edition_date)
|
||||
fifth_count = build_novel_edition(fifth, fifth_out,
|
||||
'第五卷《越过边境》阅读合订本',
|
||||
'总第89—112章,共24章;874初秋—晚秋,埃利安19岁', edition_date)
|
||||
print(f'小说112章+序章;约{full_count:,}汉字;第五卷24章约{fifth_count:,}汉字(含标题)')
|
||||
print(combined)
|
||||
print(fifth_out)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--date', required=True)
|
||||
parser.add_argument('--refresh-reading', help='由Fountain重建指定分集阅读稿,如S01E04;同时更新该集前置动作提示')
|
||||
parser.add_argument('--novel-only', action='store_true', help='只汇集当前前四卷阅读本,不更新影像剧本与录制资料')
|
||||
parser.add_argument('--novel-only', action='store_true', help='只汇集当前小说阅读本,不更新历史范围或影像资料')
|
||||
args = parser.parse_args()
|
||||
if args.novel_only:
|
||||
if args.refresh_reading:
|
||||
parser.error('--novel-only不能与--refresh-reading同时使用')
|
||||
build_four_volume_editions(args.date)
|
||||
if (NOVEL / '03_正文/第五卷/112_明天要见的人.md').is_file():
|
||||
build_five_volume_editions(args.date)
|
||||
else:
|
||||
build_four_volume_editions(args.date)
|
||||
return
|
||||
global_path = EPISODES / '全季_台词与录制总表.tsv'
|
||||
global_fields, global_rows = read_table(global_path)
|
||||
@@ -348,6 +377,8 @@ def main():
|
||||
print(f'前三卷固定范围:68章+序章;汉字约{novel_cjk:,};第三卷20章约{volume_cjk:,}汉字(含标题及原有稿次说明)')
|
||||
if (NOVEL / '03_正文/第四卷/88_只到中立站.md').is_file():
|
||||
build_four_volume_editions(args.date)
|
||||
if (NOVEL / '03_正文/第五卷/112_明天要见的人.md').is_file():
|
||||
build_five_volume_editions(args.date)
|
||||
print(f'EP02—12录制台词:{len(all_rows)};各集:{episode_counts}')
|
||||
print('已核对11集Fountain与阅读稿台词逐条一致。')
|
||||
print(full_out)
|
||||
|
||||
@@ -139,7 +139,7 @@ if ($cumulative -ne 75) { $failures.Add("Expected 75 seconds, got $cumulative")
|
||||
|
||||
$bodyStart = $scriptText.IndexOf('INT. ')
|
||||
$scriptChars = if ($bodyStart -ge 0) { [regex]::Replace($scriptText.Substring($bodyStart), '\s', '').Length } else { 0 }
|
||||
$novelFiles = @(Get-ChildItem -LiteralPath (Join-Path $projectRoot '05_小说创作/03_正文') -Filter '*.md' -File -Recurse | Where-Object { $_.Name -match '^\d{2}_' })
|
||||
$novelFiles = @(Get-ChildItem -LiteralPath (Join-Path $projectRoot '05_小说创作/03_正文') -Filter '*.md' -File -Recurse | Where-Object { $_.Name -match '^\d+_' })
|
||||
$novelChars = ($novelFiles | ForEach-Object { [regex]::Replace((Get-Content -LiteralPath $_.FullName -Raw -Encoding UTF8), '\s', '').Length } | Measure-Object -Sum).Sum
|
||||
$pngCount = @(Get-ChildItem -LiteralPath (Join-Path $projectRoot '06_AI动漫制作') -Filter '*.png' -File -Recurse).Count
|
||||
|
||||
@@ -286,21 +286,21 @@ if (($chapterIds -join ',') -ne ((1..24) -join ',')) { $failures.Add('Expected 2
|
||||
$episodeText = Read-ProjectText '06_AI动漫制作/01_改编开发/02_分集大纲/第一季_12集分集大纲.md'
|
||||
$episodeIds = @([regex]::Matches($episodeText, '(?m)^\| (\d+) \|') | ForEach-Object { [int]$_.Groups[1].Value })
|
||||
if (($episodeIds -join ',') -ne ((1..12) -join ',')) { $failures.Add('Expected 12 ordered V03 episode rows') }
|
||||
# The writing now extends through chapter 68; allow subsequent chapters without
|
||||
# freezing progress at today's count, while rejecting gaps and duplicate IDs.
|
||||
$firstVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第一卷' } | ForEach-Object { [int]$_.Name.Substring(0, 2) } | Sort-Object)
|
||||
# Parse complete numeric prefixes beyond chapter 99. Allow further chapters
|
||||
# without freezing today's total, while rejecting gaps and duplicate IDs.
|
||||
$firstVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第一卷' } | ForEach-Object { [int]($_.Name -split '_', 2)[0] } | Sort-Object)
|
||||
if (($firstVolumeIds -join ',') -ne ((0..24) -join ',')) {
|
||||
$failures.Add('Volume one must contain the prologue and chapters 1-24')
|
||||
}
|
||||
$draftIds = @($novelFiles | ForEach-Object { [int]$_.Name.Substring(0, 2) } | Sort-Object)
|
||||
$draftIds = @($novelFiles | ForEach-Object { [int]($_.Name -split '_', 2)[0] } | Sort-Object)
|
||||
if ($draftIds.Count -lt 69 -or ($draftIds -join ',') -ne ((0..($draftIds.Count - 1)) -join ',')) {
|
||||
$failures.Add('Novel draft IDs must be unique, continuous from 00 and reach at least chapter 68')
|
||||
}
|
||||
$secondVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第二卷' } | ForEach-Object { [int]$_.Name.Substring(0, 2) } | Sort-Object)
|
||||
$secondVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第二卷' } | ForEach-Object { [int]($_.Name -split '_', 2)[0] } | Sort-Object)
|
||||
if (($secondVolumeIds -join ',') -ne ((25..48) -join ',')) {
|
||||
$failures.Add('Volume two must contain chapters 25-48')
|
||||
}
|
||||
$thirdVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第三卷' } | ForEach-Object { [int]$_.Name.Substring(0, 2) } | Sort-Object)
|
||||
$thirdVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第三卷' } | ForEach-Object { [int]($_.Name -split '_', 2)[0] } | Sort-Object)
|
||||
if (($thirdVolumeIds -join ',') -ne ((49..68) -join ',')) {
|
||||
$failures.Add('Volume three must contain chapters 49-68')
|
||||
}
|
||||
@@ -309,7 +309,7 @@ $thirdOutlineIds = @([regex]::Matches($thirdOutline, '(?m)^\| (\d+) \|') | ForEa
|
||||
if (($thirdOutlineIds -join ',') -ne ($thirdVolumeIds -join ',')) {
|
||||
$failures.Add('Volume three chapter outline and prose IDs differ')
|
||||
}
|
||||
$fourthVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第四卷' } | ForEach-Object { [int]$_.Name.Substring(0, 2) } | Sort-Object)
|
||||
$fourthVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第四卷' } | ForEach-Object { [int]($_.Name -split '_', 2)[0] } | Sort-Object)
|
||||
if ($fourthVolumeIds.Count -gt 0) {
|
||||
if (($fourthVolumeIds -join ',') -ne ((69..88) -join ',')) {
|
||||
$failures.Add('Completed volume four must contain chapters 69-88')
|
||||
@@ -320,6 +320,17 @@ if ($fourthVolumeIds.Count -gt 0) {
|
||||
$failures.Add('Volume four chapter outline and prose IDs differ')
|
||||
}
|
||||
}
|
||||
$fifthVolumeIds = @($novelFiles | Where-Object { $_.Directory.Name -eq '第五卷' } | ForEach-Object { [int]($_.Name -split '_', 2)[0] } | Sort-Object)
|
||||
if ($fifthVolumeIds.Count -gt 0) {
|
||||
if (($fifthVolumeIds -join ',') -ne ((89..112) -join ',')) {
|
||||
$failures.Add('Completed volume five must contain chapters 89-112')
|
||||
}
|
||||
$fifthOutline = Read-ProjectText '05_小说创作/02_章节大纲/第五卷_章节大纲.md'
|
||||
$fifthOutlineIds = @([regex]::Matches($fifthOutline, '(?m)^\| (\d+) \|') | ForEach-Object { [int]$_.Groups[1].Value })
|
||||
if (($fifthOutlineIds -join ',') -ne ($fifthVolumeIds -join ',')) {
|
||||
$failures.Add('Volume five chapter outline and prose IDs differ')
|
||||
}
|
||||
}
|
||||
foreach ($legacy in @(
|
||||
'06_AI动漫制作/03_分镜与镜头/01_镜头表/S01E01_SC12_75秒试片镜头表.md',
|
||||
'06_AI动漫制作/04_生成方案/01_图像提示词/S01E01_SC12_关键帧提示词.md',
|
||||
|
||||
Reference in New Issue
Block a user