feat(comic): export metadata to ComicInfo.xml sidecar (bookshelf-w1or) #634
Closed
zombor
wants to merge 4 commits from
bd-bookshelf-w1or into main
pull from: bd-bookshelf-w1or
merge into: zombor:main
zombor:main
zombor:bd-bookshelf-mqavx
zombor:bd-bookshelf-t7cmm
zombor:bd-bookshelf-8l09k
zombor:bd-bookshelf-duy4m
zombor:bd-bookshelf-v8o1o
zombor:bd-bookshelf-lwfh6
zombor:bd-bookshelf-egkeh
zombor:bd-bookshelf-yh6wk
zombor:bd-bookshelf-f8gf8
zombor:bd-bookshelf-v1byv
zombor:bd-bookshelf-289dd
zombor:bd-bookshelf-ar5x7
zombor:bd-bookshelf-h4oh2.8
zombor:bd-cikiq
zombor:bd-nnb9-seeder-llm
zombor:bd-cleanup-batch
zombor:bd-bookshelf-l3dv0
zombor:bd-bookshelf-nnb9.30
zombor:bd-bookshelf-4dlia
zombor:bd-bookshelf-v2gkq
zombor:bd-bookshelf-4un29.7
zombor:bd-bookshelf-1v17h
zombor:bd-bookshelf-nnb9.29
zombor:bd-bookshelf-nnb9.13
zombor:bd-bookshelf-88rd5
zombor:bd-bookshelf-nnb9.27
zombor:bd-bookshelf-7vv09
zombor:bd-bookshelf-syyzy
zombor:bd-bookshelf-adzpx
zombor:bd-bookshelf-v3bi0
zombor:bd-bookshelf-j8pvj
zombor:bd-bookshelf-fqvh.5
zombor:bd-bookshelf-h4oh2.7
zombor:bd-bookshelf-ttfqc
zombor:bd-bookshelf-hva6t
zombor:bd-bookshelf-di2zy
zombor:bd-bookshelf-fqvh.4
zombor:bd-bookshelf-8dnq
zombor:bd-bookshelf-dbw4q
zombor:bd-bookshelf-1eg75
zombor:bd-bookshelf-jjcgz
zombor:bd-bookshelf-k4wji
zombor:bd-bookshelf-abwx.1
zombor:bd-bookshelf-qi21k.1
zombor:bd-bookshelf-dhlj4.2
zombor:bd-bookshelf-dhlj4.4
zombor:bd-bookshelf-dhlj4.1
zombor:bd-bookshelf-dhlj4.3
zombor:bd-bookshelf-s957
zombor:bd-bookshelf-mfli8
zombor:bd-bookshelf-h4oh2.2
zombor:bd-bookshelf-007p6
zombor:bd-bookshelf-ox4u6
zombor:bd-bookshelf-dfknw
zombor:bd-bookshelf-fvug6
zombor:bd-bookshelf-2ddlb
zombor:bd-bookshelf-nnb9.6
zombor:bd-bookshelf-5pyab
zombor:bd-bookshelf-qapga
zombor:bd-bookshelf-2dcn3
zombor:bd-bookshelf-64dbp
zombor:bd-bookshelf-r5dix
zombor:bd-bookshelf-nnb9.11
zombor:bd-bookshelf-nnb9.7
zombor:bd-bookshelf-s6k3o
zombor:bd-bookshelf-p8trd
zombor:bd-bookshelf-81hq
zombor:bd-bookshelf-tm38.9
zombor:bd-bookshelf-tm38.15
zombor:bd-bookshelf-tm38.11
zombor:bd-bookshelf-bxtat
zombor:bd-bookshelf-ifwpa
zombor:bd-bookshelf-bz643.7
zombor:bd-bookshelf-fip0
zombor:bd-bookshelf-0u50.2
zombor:bd-bookshelf-m35t
zombor:bd-bookshelf-bz643.6
zombor:bd-bookshelf-cd2u
zombor:bd-bookshelf-xyfk
zombor:bd-bookshelf-4un29.6
zombor:bd-bookshelf-alw8k
zombor:bd-bookshelf-dgs62
zombor:bd-bookshelf-bz643.5
zombor:bd-bookshelf-ztnqw
zombor:bd-bookshelf-ot43
zombor:bd-bookshelf-14k7f
zombor:bd-bookshelf-n1k3c
zombor:bd-bookshelf-67rri
zombor:bd-bookshelf-bz643.4
zombor:bd-bookshelf-ezivi
zombor:bd-bookshelf-eseay.13
zombor:bd-bookshelf-0u50.3
zombor:bd-bookshelf-eseay.27
zombor:bd-bookshelf-eseay.16
zombor:bd-bookshelf-eseay.7
zombor:bd-bookshelf-eseay.12
zombor:bd-bookshelf-eseay.18
zombor:bd-bookshelf-eseay.9
zombor:bd-bookshelf-eseay.22
zombor:bd-bookshelf-eseay.8
zombor:bd-bookshelf-eseay.6
zombor:bd-bookshelf-bz643.3
zombor:bd-bookshelf-v8qc
zombor:bd-bookshelf-2puu
zombor:bd-bookshelf-0u50.1
zombor:bd-bookshelf-eseay.1
zombor:bd-bookshelf-eseay.3
zombor:bd-bookshelf-y2r7
zombor:bd-bookshelf-guzv
zombor:bd-bookshelf-uiz4
zombor:bd-bookshelf-4un29.5
zombor:bd-bookshelf-d7zq
zombor:bd-bookshelf-eseay.5
zombor:bd-bookshelf-eseay.2
zombor:bd-bookshelf-eseay.4
zombor:bd-bookshelf-b96py
zombor:bd-bookshelf-4un29.4
zombor:bd-bookshelf-i34sv
zombor:bd-bookshelf-2a8v2
zombor:bd-bookshelf-bz643.1
zombor:bd-bookshelf-3brr8
zombor:bd-bookshelf-ora3c
zombor:bd-bookshelf-k56js
zombor:bd-bookshelf-me2xs
zombor:bd-bookshelf-tc4u
zombor:bd-bookshelf-4un29.3
zombor:bd-bookshelf-7w1mn
zombor:bd-bookshelf-bz643.2
zombor:bd-bookshelf-t9b1v
zombor:bd-bookshelf-7pobp
zombor:bd-bookshelf-kedq3
zombor:bd-bookshelf-sgow8
zombor:bd-bookshelf-ydjo9
zombor:bd-bookshelf-sdtvq
zombor:bd-bookshelf-wro8e
zombor:bd-bookshelf-xif3r
zombor:bd-bookshelf-0xjkz
zombor:bd-bookshelf-t4ftz
zombor:bd-bookshelf-d6a0j
zombor:bd-bookshelf-eu18m
zombor:bd-bookshelf-or2yq
zombor:bd-bookshelf-y7wy8
zombor:bd-bookshelf-49zk3
zombor:bd-bookshelf-5nrvm
zombor:bd-bookshelf-z0j58
zombor:bd-bookshelf-b8p9v
zombor:bd-bookshelf-7vrur
zombor:bd-bookshelf-w442p
zombor:bd-bookshelf-4vb3n
zombor:bd-bookshelf-nwo0v.2
zombor:bd-bookshelf-zwfeq
zombor:bd-bookshelf-r0ua
zombor:bd-bookshelf-skp0b.2
zombor:bd-bookshelf-t408q
zombor:bd-bookshelf-ubhc1
zombor:bd-bookshelf-cs2zl.3
zombor:bd-bookshelf-9snmz.3.2
zombor:bd-bookshelf-6tq2k.3
zombor:bd-bookshelf-bg8c5
zombor:bd-bookshelf-t3z2w.3
zombor:bd-bookshelf-4un29.2
zombor:bd-bookshelf-stwfu
zombor:bd-bookshelf-skp0b.1
zombor:bd-bookshelf-6tq2k.2
zombor:bd-bookshelf-b1mbr.6
zombor:bd-bookshelf-ti0zf
zombor:bd-bookshelf-dc11r
zombor:bd-bookshelf-bar26
zombor:bd-bookshelf-lwj7a
zombor:bd-bookshelf-gsebk
zombor:bd-bookshelf-ojr0m
zombor:bd-bookshelf-4un29.1
zombor:bd-bookshelf-hq7ty
zombor:bd-bookshelf-9snmz.2.1
zombor:bd-bookshelf-b9x27
zombor:bd-bookshelf-nwo0v.1
zombor:bd-bookshelf-t582g.3.3
zombor:bd-bookshelf-wf21j
zombor:bd-bookshelf-pcskn
zombor:bd-bookshelf-lk0f7
zombor:bd-bookshelf-9snmz.4.1
zombor:bd-bookshelf-9snmz.3.1
zombor:bd-bookshelf-w5s4b
zombor:bd-bookshelf-t582g.1.2
zombor:bd-bookshelf-2kb7e
zombor:bd-bookshelf-t582g.5.1
zombor:bd-bookshelf-t582g.1.1
zombor:bd-bookshelf-x7hym
zombor:bd-bookshelf-qgd90.11
zombor:bd-bookshelf-t582g.5.2
zombor:bd-bookshelf-l11xh
zombor:bd-bookshelf-qgd90.12
zombor:bd-bookshelf-qgd90.13
zombor:bd-bookshelf-qgd90.10
zombor:bd-bookshelf-t582g.3.1
zombor:bd-bookshelf-t582g.6.3
zombor:bd-bookshelf-kyk09
zombor:bd-bookshelf-qgd90.8
zombor:bd-bookshelf-qgd90.9
zombor:bd-bookshelf-7wnz1
zombor:bd-bookshelf-t582g.2.2
zombor:bd-bookshelf-t582g.6.2
zombor:bd-bookshelf-t582g.4.2
zombor:bd-bookshelf-t582g.6.1
zombor:bd-bookshelf-t582g.13
zombor:bd-bookshelf-t582g.12
zombor:bd-bookshelf-t582g.5.3
zombor:bd-bookshelf-t582g.3.2
zombor:bd-bookshelf-t582g.11
zombor:bd-bookshelf-9snmz.1.2
zombor:bd-bookshelf-9snmz.1.3
zombor:bd-bookshelf-9snmz.1.1
zombor:bd-bookshelf-t3z2w.6
zombor:bd-bookshelf-t582g.9
zombor:bd-bookshelf-t582g.7
zombor:bd-bookshelf-t582g.2.1
zombor:bd-bookshelf-9snmz.1.4
zombor:bd-bookshelf-t582g.10
zombor:bd-bookshelf-t582g.4.3
zombor:bd-bookshelf-t582g.14
zombor:bd-bookshelf-t582g.4.1
zombor:bd-bookshelf-zedtf
zombor:bd-bookshelf-t3z2w.4
zombor:bd-bookshelf-lems6
zombor:bd-bookshelf-lrlp6
zombor:bd-bookshelf-qgd90.5
zombor:bd-bookshelf-cs2zl.2
zombor:bd-bookshelf-wtsp.7
zombor:bd-bookshelf-qgd90.3
zombor:bd-bookshelf-sgv1d
zombor:bd-bookshelf-xrfax
zombor:bd-bookshelf-np8wh
zombor:bd-bookshelf-nosq3
zombor:bd-bookshelf-6d4km
zombor:bd-bookshelf-qgd90.2
zombor:bd-bookshelf-uwob4
zombor:bd-bookshelf-qgd90.1
zombor:bd-bookshelf-x05zh
zombor:bd-bookshelf-8br47
zombor:bd-bookshelf-t3z2w.2
zombor:bd-bookshelf-t8ovd
zombor:bd-bookshelf-t3z2w.1
zombor:bd-bookshelf-rhvsi
zombor:bd-bookshelf-o4xwc
zombor:bd-bookshelf-66xxp
zombor:bd-bookshelf-3gnqi
zombor:bd-bookshelf-b0hoe
zombor:bd-bookshelf-wtsp.1
zombor:bd-bookshelf-yyft
zombor:bd-bookshelf-cs2zl.1
zombor:bd-bookshelf-onx3v
zombor:bd-bookshelf-17i2p
zombor:bd-bookshelf-k4jrb
zombor:bd-bookshelf-c75cx
zombor:bd-bookshelf-33oo
zombor:bd-bookshelf-nnb9.4
zombor:bd-bookshelf-uoz1
zombor:bd-bookshelf-pwkx.2
zombor:bd-bookshelf-w2mii
zombor:bd-bookshelf-tm38.10
zombor:bd-bookshelf-j58r
zombor:bd-bookshelf-frlqv
zombor:bd-bookshelf-nymf0
zombor:bd-bookshelf-74rm
zombor:bd-bookshelf-6tq2k.1
zombor:bd-bookshelf-r24bc.3
zombor:bd-bookshelf-tm38.2
zombor:bd-bookshelf-b1mbr.3
zombor:bd-bookshelf-v1ap
zombor:bd-bookshelf-zgje6
zombor:bd-bookshelf-6bt0f
zombor:bd-bookshelf-rbaj
zombor:bd-bookshelf-b1mbr.4
zombor:bd-bookshelf-du8hq
zombor:bd-bookshelf-tm38.5
zombor:bd-bookshelf-qnswo
zombor:bd-bookshelf-qo6ly.2
zombor:bd-bookshelf-qo6ly.5
zombor:bd-bookshelf-qo6ly.7
zombor:bd-bookshelf-qo6ly.6
zombor:bd-bookshelf-aatkt
zombor:bd-bookshelf-7w29g
zombor:bd-bookshelf-l5a46
zombor:bd-bookshelf-npcxc
zombor:bd-bookshelf-qo6ly.4
zombor:bd-bookshelf-qo6ly.3
zombor:bd-bookshelf-1ka7f
zombor:bd-bookshelf-dzrgz
zombor:bd-bookshelf-qo6ly.1
zombor:bd-bookshelf-xb1xn
zombor:bd-bookshelf-qo6ly.8
zombor:bd-bookshelf-m3yzn
zombor:bd-bookshelf-2yn0c-p2
zombor:bd-bookshelf-2yn0c
zombor:bd-bookshelf-lbmtp
zombor:bd-bookshelf-7c8d5
zombor:bd-bookshelf-vsf6.2
zombor:bd-bookshelf-85a3a
zombor:bd-bookshelf-rval6
zombor:bd-bookshelf-bpb9.2
zombor:bd-bookshelf-fqvh.2
zombor:bd-bookshelf-8i4p
zombor:bd-bookshelf-fr9s2
zombor:bd-bookshelf-wl6by
zombor:bd-bookshelf-80j52
zombor:bd-bookshelf-r24bc.2
zombor:bd-bookshelf-0v44o.3
zombor:bd-bookshelf-bu5v
zombor:bd-bookshelf-b1mbr.5
zombor:bd-bookshelf-tm38.7
zombor:bd-bookshelf-kgebl
zombor:bd-bookshelf-7wgxa
zombor:bd-bookshelf-hqemh
zombor:bd-bookshelf-36hv1
zombor:bd-bookshelf-86v1x
zombor:bd-bookshelf-b1mbr.2
zombor:bd-bookshelf-a6qot
zombor:bd-reviewer-demo-gate
zombor:bd-bookshelf-wb7f2
zombor:bd-bookshelf-me0ix
zombor:bd-bookshelf-10th0
zombor:bd-bookshelf-7ocsw
zombor:bd-bookshelf-hflt3
zombor:bd-bookshelf-m16mq
zombor:bd-bookshelf-30pry
zombor:bd-bookshelf-mcqt8
zombor:bd-bookshelf-3q9hy
zombor:bd-bookshelf-lj69z.4
zombor:bd-bookshelf-dydjz
zombor:bd-bookshelf-7obo7
zombor:bd-bookshelf-lj69z.6
zombor:bd-bookshelf-1txhu
zombor:bd-bookshelf-zvlod
zombor:bd-bookshelf-d1866
zombor:bd-bookshelf-lj69z.3
zombor:bd-bookshelf-lj69z.2
zombor:bd-bookshelf-36j4z
zombor:bd-bookshelf-63dw.17
zombor:bd-bookshelf-m7n5c
zombor:bd-bookshelf-4jilj
zombor:bd-bookshelf-nngwa
zombor:bd-bookshelf-63dw.16
zombor:bd-bookshelf-rvfcj
zombor:bd-bookshelf-hkgs0
zombor:bd-bookshelf-kentd
zombor:bd-bookshelf-q9n8e
zombor:bd-bookshelf-j46t4
zombor:bd-bookshelf-4lli2
zombor:bd-bookshelf-lj69z.5
zombor:bd-bookshelf-hlalw
zombor:bd-bookshelf-jcb79
zombor:bd-bookshelf-gcy0e
zombor:bd-bookshelf-9ij4c
zombor:bd-bookshelf-lj69z.1
zombor:bd-bookshelf-wxxk7
zombor:bd-bookshelf-2q3jo
zombor:bd-bookshelf-5qv5.3
zombor:bd-bookshelf-ng7e5
zombor:bd-bookshelf-02gem
zombor:bd-bookshelf-zvcf
zombor:bd-bookshelf-5qv5.2
zombor:bd-bookshelf-pwkx.4
zombor:bd-bookshelf-yhfqd
zombor:bd-bookshelf-0okxi
zombor:bd-bookshelf-pwkx.3
zombor:bd-bookshelf-vhqg5
zombor:bd-bookshelf-tm38.13
zombor:bd-bookshelf-vsf6.4
zombor:bd-bookshelf-epa9z
zombor:bd-bookshelf-ju77u
zombor:bd-bookshelf-wivx.2
zombor:bd-bookshelf-5qv5.1
zombor:bd-bookshelf-vgbmo.2
zombor:bd-bookshelf-0v44o.2
zombor:bd-bookshelf-7ahb0
zombor:bd-bookshelf-g81y
zombor:bd-bookshelf-ebbx
zombor:bd-bookshelf-22pag
zombor:bd-bookshelf-c0nvx
zombor:bd-bookshelf-c2b5p
zombor:bd-bookshelf-6ze9n
zombor:bd-bookshelf-px2u9
zombor:bd-bookshelf-jqxvt
zombor:bd-bookshelf-it6qc
zombor:bd-bookshelf-f9po3
zombor:bd-bookshelf-vgbmo.1
zombor:bd-bookshelf-j49zv
zombor:bd-bookshelf-8k02l
zombor:bd-bookshelf-6nrjb
zombor:bd-bookshelf-mzvjv
zombor:bd-bookshelf-yco0j
zombor:bd-bookshelf-r24bc.1
zombor:bd-bookshelf-oi1l2
zombor:bd-bookshelf-0v44o.1
zombor:bd-bookshelf-q75pc.1
zombor:bd-bookshelf-2tqlm
zombor:bd-bookshelf-q2e6j
zombor:bd-bookshelf-tvx5
zombor:bd-bookshelf-q3urm
zombor:bd-bookshelf-af1ug
zombor:bd-bookshelf-gr8c
zombor:bd-bookshelf-w9n1
zombor:bd-bookshelf-7cj1
zombor:bd-bookshelf-x1qd
zombor:bd-bookshelf-tm5g1
zombor:bd-bookshelf-h7yv
zombor:bd-bookshelf-osnt
zombor:bd-bookshelf-63dw.15
zombor:bd-bookshelf-63dw.14
zombor:bd-bookshelf-63dw.13
zombor:bd-bookshelf-63dw.12
zombor:bd-bookshelf-63dw.11
zombor:bd-bookshelf-jnsce
zombor:bd-bookshelf-0zbt
zombor:bd-bookshelf-z9s8.3
zombor:bd-bookshelf-59k1
zombor:bd-bookshelf-sq9g
zombor:bd-bookshelf-mg8b
zombor:bd-bookshelf-nnmp
zombor:bd-bookshelf-t1j0
zombor:bd-bookshelf-km3w
zombor:bd-bookshelf-50yv
zombor:bd-bookshelf-trj6
zombor:bd-bookshelf-vguw.15
zombor:bd-bookshelf-ndik
zombor:bd-bookshelf-z9s8.2
zombor:bd-bookshelf-ldxk
zombor:bd-bookshelf-z9s8.1
zombor:bd-bookshelf-9il8
zombor:bd-bookshelf-53zz
zombor:bd-bookshelf-tm38.8
zombor:bd-bookshelf-tm38.1
zombor:bd-bookshelf-r89h
zombor:bd-bookshelf-wdow
zombor:bd-bookshelf-o6np
zombor:bd-bookshelf-qowx
zombor:bd-bookshelf-ed3d
zombor:bd-bookshelf-nrup
zombor:bd-bookshelf-ke3w
zombor:bd-bookshelf-5c2h
zombor:bd-bookshelf-9a2z
zombor:bd-bookshelf-8oj1
zombor:bd-bookshelf-gbaz
zombor:bd-bookshelf-dy0a
zombor:bd-bookshelf-p4nm
zombor:bd-bookshelf-ef27
zombor:bd-bookshelf-4hu8
zombor:bd-bookshelf-mrjp
zombor:bd-bookshelf-23v3
zombor:bd-bookshelf-1hdb
zombor:bd-bookshelf-v33b
zombor:bd-bookshelf-wfx9
zombor:bd-bookshelf-tm38.6
zombor:bd-bookshelf-i6yc
zombor:bd-bookshelf-wkwd
zombor:bd-bookshelf-qwvg
zombor:bd-bookshelf-3hdz
zombor:bd-bookshelf-rwvk
zombor:bd-bookshelf-6pit
zombor:bd-bookshelf-ihze
zombor:bd-bookshelf-hkdy
zombor:bd-bookshelf-l1nn
zombor:bd-bookshelf-4jla
zombor:bd-bookshelf-0115
zombor:bd-bookshelf-gs7j
zombor:bd-bookshelf-nnb9.17
zombor:bd-bookshelf-nnb9.28
zombor:bd-bookshelf-nfkm
zombor:bd-bookshelf-8u2q
zombor:bd-bookshelf-l6cz
zombor:bd-bookshelf-fwpb
zombor:bd-bookshelf-tpnl
zombor:bd-bookshelf-cwz9
zombor:bd-bookshelf-4el7
zombor:bd-bookshelf-drq3
zombor:bd-bookshelf-u6a5
zombor:bd-bookshelf-pwkx.1
zombor:bd-bookshelf-rnvl
zombor:bd-bookshelf-3493
zombor:bd-bookshelf-xqk5
zombor:bd-bookshelf-b8oi
zombor:bd-bookshelf-ybzp
zombor:bd-bookshelf-xvdi
zombor:bd-bookshelf-hd0y.2
zombor:bd-bookshelf-c51j
zombor:bd-bookshelf-hd0y.1
zombor:bd-bookshelf-t19a
zombor:bd-bookshelf-9yl4
zombor:bd-bookshelf-mwz5
zombor:bd-bookshelf-ic7s
zombor:bd-bookshelf-di1h
zombor:bd-bookshelf-l2ln
zombor:bd-bookshelf-uamr
zombor:bd-bookshelf-2qfp
zombor:bd-bookshelf-d3x0
zombor:bd-bookshelf-nskf
zombor:bd-bookshelf-vzc6
zombor:bd-bookshelf-76yy
zombor:bd-bookshelf-i16w
zombor:bd-bookshelf-32if
zombor:bd-bookshelf-ond2
zombor:bd-bookshelf-nbfw
zombor:bd-bookshelf-92us
zombor:bd-bookshelf-4xxe
zombor:bd-bookshelf-wivx.1
zombor:bd-bookshelf-njg4.1
zombor:bd-bookshelf-1725
zombor:bd-bookshelf-ivtz.3
zombor:bd-bookshelf-ivtz.2
zombor:bd-bookshelf-5i5b
zombor:bd-bookshelf-2v3k
zombor:bd-bookshelf-qmqd
zombor:bd-bookshelf-9by3
zombor:bd-bookshelf-qsvf
zombor:bd-bookshelf-bn7r
zombor:bd-bookshelf-6e4w
zombor:bd-bookshelf-bsbn
zombor:bd-bookshelf-ivtz.1
zombor:bd-bookshelf-f7at
zombor:bd-bookshelf-660k
zombor:bd-bookshelf-9gbq
zombor:bd-bookshelf-tdvx
zombor:bd-bookshelf-uj5h.2
zombor:bd-bookshelf-3rny
zombor:bd-bookshelf-uj5h.4
zombor:bd-bookshelf-vbs7
zombor:bd-bookshelf-kpbh
zombor:bd-bookshelf-srv2
zombor:bd-bookshelf-6dxk
zombor:bd-bookshelf-h1yj
zombor:bd-bookshelf-b5xs
zombor:bd-bookshelf-z7gq
zombor:bd-bookshelf-pls2
zombor:bd-bookshelf-hxwe
zombor:bd-bookshelf-nuun
zombor:bd-bookshelf-bbsd.8
zombor:bd-bookshelf-bbsd.1
zombor:bd-bookshelf-bbsd.6
zombor:bd-bookshelf-xjbg
zombor:bd-bookshelf-uj5h.1
zombor:bd-bookshelf-bbsd.7
zombor:bd-bookshelf-bbsd.3
zombor:bd-bookshelf-vavz
zombor:bd-bookshelf-vumd
zombor:bd-bookshelf-8dry
zombor:bd-bookshelf-fqvh.1
zombor:bd-bookshelf-bbsd.5
zombor:bd-bookshelf-bbsd.2
zombor:bd-bookshelf-bbsd.4
zombor:bd-bookshelf-v3ks
zombor:bd-bookshelf-28s0
zombor:bd-bookshelf-rppy
zombor:bd-bookshelf-s7kr
zombor:bd-bookshelf-6krh
zombor:bd-bookshelf-fq9r
zombor:bd-bookshelf-n51o
zombor:bd-bookshelf-4rvz
zombor:bd-bookshelf-cehm
zombor:bd-bookshelf-scev
zombor:bd-bookshelf-bkzy
zombor:bd-bookshelf-amwv
zombor:bd-bookshelf-9u56
zombor:bd-bookshelf-t5xp
zombor:bd-bookshelf-63dw.10
zombor:bd-bookshelf-0szi
zombor:bd-bookshelf-5kje
zombor:bd-bookshelf-fx7k
zombor:bd-bookshelf-y6z7
zombor:bd-bookshelf-zii7
zombor:bd-bookshelf-s8jh
zombor:bd-bookshelf-iso0
zombor:bd-bookshelf-ug3n
zombor:bd-bookshelf-rpr4
zombor:bd-bookshelf-b6je
zombor:bd-bookshelf-u8fd
zombor:bd-bookshelf-slof
zombor:bd-bookshelf-u5q4
zombor:bd-bookshelf-nu1i
zombor:bd-bookshelf-81x8
zombor:bd-bookshelf-vnu3
zombor:bd-bookshelf-ry66
zombor:bd-bookshelf-7mzg
zombor:bd-bookshelf-lj5p
zombor:bd-bookshelf-81gk
zombor:bd-bookshelf-poza
zombor:bd-bookshelf-v7r0
zombor:bd-bookshelf-3u1y
zombor:bd-bookshelf-y1nh
zombor:bd-bookshelf-94sd
zombor:bd-bookshelf-ssbz
zombor:bd-bookshelf-d4yf.2
zombor:bd-bookshelf-tal7
zombor:bd-bookshelf-h411
zombor:bd-bookshelf-mpfv
zombor:bd-bookshelf-o1qm
zombor:bd-bookshelf-0nyl
zombor:bd-bookshelf-63dw.9
zombor:bd-bookshelf-lwh6
zombor:bd-bookshelf-cp6i
zombor:bd-bookshelf-qdlw
zombor:bd-bookshelf-vbtl
zombor:bd-bookshelf-nqp0.3
zombor:bd-bookshelf-nqp0.1
zombor:bd-bookshelf-jxqf
zombor:bd-bookshelf-63dw.8
zombor:bd-bookshelf-d4yf.1
zombor:bd-bookshelf-pmd7
zombor:bd-bookshelf-jjj3
zombor:bd-bookshelf-5xcs.2
zombor:bd-bookshelf-nnb9.9
zombor:bd-bookshelf-wbf2
zombor:bd-bookshelf-7lsm
zombor:bd-bookshelf-5xcs.1
zombor:bd-bookshelf-ocjj
zombor:bd-bookshelf-htpc.2
zombor:bd-bookshelf-nnb9.12
zombor:bd-bookshelf-nnb9.10
zombor:bd-bookshelf-qnmg
zombor:bd-bookshelf-0ypn
zombor:bd-bookshelf-nnb9.26
zombor:bd-bookshelf-nnb9.19
zombor:bd-bookshelf-nnb9.22
zombor:bd-bookshelf-bpb9.1
zombor:bd-bookshelf-nnb9.16
zombor:bd-bookshelf-htpc.3
zombor:bd-bookshelf-zc7j
zombor:bd-bookshelf-nnb9.18
zombor:bd-bookshelf-uydp
zombor:bd-bookshelf-abwx
zombor:bd-bookshelf-nnb9.21
zombor:bd-bookshelf-3j83
zombor:bd-bookshelf-htpc.1
zombor:bd-bookshelf-nnb9.23
zombor:bd-bookshelf-9yut
zombor:bd-bookshelf-dziq
zombor:bd-bookshelf-1st
zombor:bd-bookshelf-8dp6
zombor:bd-bookshelf-ziz3
zombor:bd-bookshelf-fgkh
zombor:bd-bookshelf-nnb9.2
zombor:bd-bookshelf-nnb9.24
zombor:bd-bookshelf-1gkx
zombor:bd-bookshelf-e47e.1
zombor:bd-bookshelf-hh9z
zombor:bd-bookshelf-v1to
zombor:bd-bookshelf-m0g7
zombor:bd-bookshelf-fjkw
zombor:bd-bookshelf-vyya.3
zombor:bd-bookshelf-vqy9.20
zombor:bd-bookshelf-tdtj
zombor:bd-bookshelf-4ywp
zombor:bd-bookshelf-lw6t
zombor:bd-bookshelf-qy9b
zombor:bd-bookshelf-4op.3.5
zombor:bd-bookshelf-av3c
zombor:bd-bookshelf-y0h8
zombor:bd-bookshelf-nrl3
zombor:bd-bookshelf-04kb
zombor:bd-bookshelf-8czw
zombor:bd-bookshelf-rcgw
zombor:bd-bookshelf-skgs
zombor:bd-bookshelf-vyya.2
zombor:bd-bookshelf-vf83
zombor:bd-bookshelf-bimx
zombor:bd-bookshelf-lkra
zombor:bd-bookshelf-74qg
zombor:bd-bookshelf-061u
zombor:bd-bookshelf-qmhj
zombor:bd-bookshelf-63dw.7
zombor:bd-bookshelf-djaf
zombor:bd-bookshelf-2sjm
zombor:bd-bookshelf-3f0r.10
zombor:bd-bookshelf-9au8
zombor:bd-bookshelf-2hoy
zombor:bd-bookshelf-hynl
zombor:bd-bookshelf-qknn
zombor:bd-bookshelf-vqy9.3
zombor:bd-bookshelf-xn31
zombor:bd-bookshelf-vyya.1
zombor:bd-bookshelf-yaoi
zombor:bd-bookshelf-t1is
zombor:bd-bookshelf-f1lh
zombor:bd-bookshelf-bvmy
zombor:bd-bookshelf-vqy9-batch
zombor:bd-bookshelf-3f0r.5
zombor:bd-bookshelf-3f0r.11
zombor:bd-bookshelf-63dw.6
zombor:bd-bookshelf-o0m9
zombor:bd-bookshelf-63dw.5
zombor:bd-bookshelf-4op.11.3
zombor:bd-bookshelf-l7kx
zombor:bd-bookshelf-eccn.2
zombor:bd-bookshelf-63dw.4
zombor:bd-bookshelf-vqy9.9
zombor:bd-bookshelf-z9xy
zombor:bd-bookshelf-u7vb.4
zombor:bd-bookshelf-qzgu
zombor:bd-bookshelf-vqy9.8
zombor:bd-bookshelf-8uas
zombor:bd-bookshelf-3f0r.3
zombor:bd-bookshelf-etkw.13
zombor:bd-bookshelf-etkw.14
zombor:bd-bookshelf-4op.11.2
zombor:bd-bookshelf-uk9f
zombor:bd-bookshelf-etkw.12
zombor:bd-bookshelf-r5w2
zombor:bd-bookshelf-9gsf
zombor:bd-bookshelf-wh79
zombor:bd-bookshelf-jsng
zombor:bd-bookshelf-rqun
zombor:bd-bookshelf-hvk9
zombor:bd-bookshelf-nvnq
zombor:bd-bookshelf-xrpd
zombor:bd-bookshelf-9yjy
zombor:bd-bookshelf-0b1o
zombor:bd-bookshelf-tosp
zombor:bd-bookshelf-ezqn
zombor:bd-bookshelf-xwi0
zombor:bd-bookshelf-tvgm
zombor:bd-bookshelf-3f0r.9
zombor:bd-bookshelf-etkw.11
zombor:bd-bookshelf-vqy9.19
zombor:bd-bookshelf-etkw.10
zombor:bd-bookshelf-65fk
zombor:bd-bookshelf-u7vb.3
zombor:bd-bookshelf-quq6
zombor:bd-bookshelf-4np8
zombor:bd-bookshelf-4gae
zombor:bd-bookshelf-4fjs.2
zombor:bd-bookshelf-vqy9.12
zombor:bd-bookshelf-vqy9.15
zombor:bd-bookshelf-vqy9.13
zombor:bd-bookshelf-vqy9.2
zombor:bd-bookshelf-etkw.9
zombor:bd-bookshelf-etkw.8
zombor:bd-bookshelf-63dw.3
zombor:bd-bookshelf-3v97
zombor:bd-bookshelf-63dw.2
zombor:bd-bookshelf-c15a.6
zombor:bd-bookshelf-aulh
zombor:bd-bookshelf-etkw.7
zombor:bd-bookshelf-0ai8
zombor:bd-bookshelf-63dw.1
zombor:bd-bookshelf-etkw.6
zombor:bd-bookshelf-rzlf
zombor:bd-bookshelf-e4mq
zombor:bd-bookshelf-4ztq.2
zombor:bd-bookshelf-evno
zombor:bd-bookshelf-etkw.5
zombor:bd-bookshelf-h2af
zombor:bd-bookshelf-3f0r.7
zombor:bd-bookshelf-6edv
zombor:bd-bookshelf-pytb
zombor:bd-bookshelf-0q61
zombor:bd-bookshelf-3hcm
zombor:bd-bookshelf-hei6
zombor:bd-bookshelf-1257.1
zombor:bd-bookshelf-gxiq
zombor:bd-bookshelf-etkw.4
zombor:bd-bookshelf-y59n.5
zombor:bd-bookshelf-etkw.3
zombor:bd-bookshelf-rfru
zombor:bd-bookshelf-55dd.2
zombor:bd-bookshelf-d61z
zombor:bd-bookshelf-vqy9.7
zombor:bd-bookshelf-w3e2
zombor:bd-cleanup-sweep
zombor:bd-bookshelf-1x1l
zombor:bd-bookshelf-ts96
zombor:bd-bookshelf-vqy9.5
zombor:bd-bookshelf-s885
zombor:bd-bookshelf-4ztq.1
zombor:bd-bookshelf-wzqw
zombor:bd-bookshelf-3f0r.8
zombor:bd-bookshelf-vqy9.6
zombor:bd-bookshelf-23na
zombor:bd-bookshelf-0ynf
zombor:bd-bookshelf-55dd.1
zombor:bd-bookshelf-n89u.2
zombor:bd-bookshelf-n89u.3
zombor:bd-bookshelf-xcck
zombor:bd-bookshelf-f3yy
zombor:bd-bookshelf-nre9
zombor:bd-bookshelf-c15a.5
zombor:bd-bookshelf-06b7
zombor:bd-bookshelf-3jrv
zombor:bd-bookshelf-3jrv-rebased
zombor:bd-bookshelf-luo3
zombor:bd-bookshelf-n89u.1
zombor:bd-bookshelf-lv9s
zombor:bd-bookshelf-aq0a
zombor:bd-bookshelf-fi2u
zombor:bd-bookshelf-d7es
zombor:bd-bookshelf-irrt
zombor:bd-bookshelf-u7vb.2
zombor:bd-bookshelf-3f0r.6
zombor:bd-bookshelf-vqy9.4
zombor:bd-bookshelf-jh5d
zombor:bd-bookshelf-83i1
zombor:bd-bookshelf-yc8k
zombor:bd-bookshelf-u7vb.1
zombor:bd-bookshelf-43bh
zombor:bd-bookshelf-e0t0
zombor:bd-bookshelf-etkw.2
zombor:bd-bookshelf-5rj3
zombor:bd-bookshelf-zurw
zombor:bd-bookshelf-88oe
zombor:bd-bookshelf-etkw.1
zombor:bd-bookshelf-gf14
zombor:bd-bookshelf-tswu
zombor:bd-bookshelf-d17j
zombor:bd-bookshelf-2xfi
zombor:bd-bookshelf-q14o
zombor:bd-bookshelf-qfjk
zombor:bd-bookshelf-d1x3.3
zombor:bd-bookshelf-aox5
zombor:bd-bookshelf-2p2m
zombor:bd-bookshelf-uuew
zombor:bd-bookshelf-sjy4
zombor:bd-bookshelf-orxk
zombor:bd-bookshelf-72g7
zombor:bd-bookshelf-gzqz
zombor:bd-bookshelf-o0uh
zombor:bd-bookshelf-3f0r.4
zombor:bd-bookshelf-jmn7.4.2
zombor:bd-bookshelf-jmn7.6
zombor:bd-bookshelf-kfi6
zombor:bd-bookshelf-ptbo
zombor:bd-bookshelf-pd9x
zombor:bd-bookshelf-3f0r.2
zombor:bd-bookshelf-7hc1
zombor:bd-bookshelf-jmn7.7
zombor:bd-bookshelf-l5mo.3
zombor:bd-bookshelf-uib3.1
zombor:bd-bookshelf-l5mo.2
zombor:bd-bookshelf-ubad
zombor:bd-bookshelf-3f0r.1
zombor:bd-bookshelf-l5mo.1
zombor:bd-bookshelf-jmn7.4.1
zombor:bd-bookshelf-g3y8
zombor:bd-bookshelf-lv0a
zombor:bd-bookshelf-bp34
zombor:bd-bookshelf-4op.11.1
zombor:bd-bookshelf-72gh
zombor:bd-bookshelf-hsf2
zombor:bd-bookshelf-pmfb
zombor:bd-bookshelf-8xhu
zombor:bd-bookshelf-vguw.7
zombor:bd-bookshelf-nb5x
zombor:bd-bookshelf-m8mh
zombor:bd-bookshelf-ubre
zombor:bd-bookshelf-vguw.6
zombor:bd-bookshelf-zw7g
zombor:bd-zw7g
zombor:bd-bookshelf-99n8
zombor:bd-bookshelf-hj9.3
zombor:bd-bookshelf-xhqy
zombor:bd-bookshelf-4op.10
zombor:bd-bookshelf-lt2p
zombor:bd-bookshelf-c15a.3
zombor:bd-bookshelf-4op.6
zombor:bd-bookshelf-d1x3.2
zombor:bd-bookshelf-4op.9
zombor:bd-bookshelf-g3rl
zombor:bd-bookshelf-senm.4
zombor:bd-bookshelf-r6lx.2
zombor:bd-bookshelf-pogw
zombor:bd-bookshelf-cizu
zombor:bd-bookshelf-hcyq
zombor:bd-bookshelf-d1x3.1
zombor:bd-bookshelf-7rz7
zombor:bd-bookshelf-j4xx
zombor:bd-bookshelf-y59n.3
zombor:bd-bookshelf-senm.3
zombor:bd-bookshelf-y59n.2
zombor:bd-bookshelf-1s0y
zombor:bd-bookshelf-9q4t
zombor:bd-bookshelf-senm.2
zombor:bd-bookshelf-iyv2
zombor:bd-bookshelf-uyem
zombor:bd-bookshelf-7akw
zombor:bd-bookshelf-d1x3.5
zombor:bd-bookshelf-cojh
zombor:bd-bookshelf-r6lx.1
zombor:bd-bookshelf-d1x3.4
zombor:bd-bookshelf-c15a.4
zombor:bd-bookshelf-dz34
zombor:bd-bookshelf-ku5n
zombor:bd-bookshelf-qebx
zombor:bd-bookshelf-yfnr2
zombor:bd-bookshelf-c5dv
zombor:bd-bookshelf-c15a.2
zombor:bd-bookshelf-l4jy
zombor:bd-bookshelf-0sha
zombor:bd-bookshelf-yfnr
zombor:bd-bookshelf-4xvk
zombor:bd-bookshelf-5adv
zombor:bd-bookshelf-v726
zombor:bd-bookshelf-c15a.1
zombor:bd-bookshelf-etwt
zombor:bd-bookshelf-ae60
zombor:bd-bookshelf-a9uk
zombor:bd-bookshelf-ilm7
zombor:bd-bookshelf-u5wp
zombor:bd-bookshelf-4fjs.1
zombor:bd-bookshelf-effh
zombor:bd-bookshelf-z6c7
zombor:bd-bookshelf-eh09
zombor:bd-bookshelf-qjty
zombor:bd-bookshelf-3tor
zombor:bd-bookshelf-q8f4
zombor:bd-bookshelf-kmqq
zombor:bd-bookshelf-tzsy
zombor:bd-bookshelf-qfff.8
zombor:bd-bookshelf-qfff.5
zombor:bd-bookshelf-qfff.7
zombor:bd-bookshelf-qfff.4
zombor:bd-bookshelf-qfff.6
zombor:bd-bookshelf-h97u
zombor:bd-bookshelf-qfff.9
zombor:bd-bookshelf-qfff.1
zombor:bd-bookshelf-qfff.3
zombor:bd-bookshelf-qfff.2
zombor:bd-bookshelf-q9sg
zombor:bd-bookshelf-cvak.1
zombor:bd-bookshelf-nkni
zombor:bd-bookshelf-4hep
zombor:bd-bookshelf-3g0l
zombor:bd-bookshelf-bnuz
zombor:bd-bookshelf-tr2i
zombor:bd-bookshelf-kxyu
zombor:bd-bookshelf-o1v2
zombor:bd-bookshelf-nage
zombor:bd-bookshelf-uij9
zombor:bd-bookshelf-1utg
zombor:bd-bookshelf-8cu.2
zombor:bd-bookshelf-e5qr
zombor:bd-bookshelf-sw5a
zombor:bd-bookshelf-l94s
zombor:bd-bookshelf-5455
zombor:bd-bookshelf-rdcc
zombor:bd-bookshelf-81q5
zombor:bd-bookshelf-jgr1.3
zombor:bd-bookshelf-8cu.5
zombor:bd-bookshelf-htlp
zombor:bd-bookshelf-4y3y.5
zombor:bd-bookshelf-8fiv
zombor:bd-bookshelf-jgr1.2
zombor:bd-bookshelf-47m9
zombor:bd-bookshelf-dwt.7
zombor:bd-bookshelf-2i6b
zombor:bd-bookshelf-50z.6
zombor:bd-bookshelf-phay
zombor:bd-bookshelf-xtnx
zombor:bd-bookshelf-h448
zombor:bd-bookshelf-50z.7
zombor:bd-bookshelf-mtxh.6
zombor:bd-bookshelf-ptvk
zombor:bd-bookshelf-tv2h
zombor:bd-bookshelf-jgr1.1
zombor:bd-bookshelf-66to
zombor:bd-bookshelf-clwi
zombor:bd-bookshelf-wy3d
zombor:bd-bookshelf-xqdp
zombor:bd-bookshelf-j4v4
zombor:bd-bookshelf-9i06
zombor:bd-bookshelf-dj2u
zombor:bd-bookshelf-uz59
zombor:bd-bookshelf-jhqh
zombor:bd-bookshelf-hoxb
zombor:bd-bookshelf-8cu.4
zombor:bd-bookshelf-nki1
zombor:bd-bookshelf-cpxo
zombor:bd-bookshelf-lplk
zombor:bd-bookshelf-v1at
zombor:bd-bookshelf-hnen
zombor:bd-bookshelf-cupd
zombor:bd-bookshelf-oxau
zombor:bd-bookshelf-nmkq
zombor:bd-bookshelf-mjbo.4
zombor:bd-bookshelf-izde
zombor:bd-bookshelf-4y3y.4
zombor:bd-bookshelf-bu7h
zombor:bd-bookshelf-ixav
zombor:bd-bookshelf-491n
zombor:bd-bookshelf-93cc
zombor:bd-bookshelf-gdnn
zombor:bd-bookshelf-qk72.2
zombor:bd-bookshelf-cs9.2
zombor:bd-bookshelf-a977
zombor:bd-bookshelf-d7d5
zombor:bd-bookshelf-8cu.3
zombor:bd-bookshelf-4op.3.6
zombor:bd-bookshelf-w59y
zombor:bd-bookshelf-dwqu
zombor:bd-bookshelf-jdls
zombor:bd-bookshelf-jmn7.3
zombor:bd-bookshelf-37ef.1
zombor:bd-bookshelf-qk72.1
zombor:bd-bookshelf-4op.3.3
zombor:bd-bookshelf-4op.3.2
zombor:bd-bookshelf-8cu.1
zombor:bd-bookshelf-xm84.1
zombor:bd-bookshelf-4op.3.1
zombor:bd-bookshelf-qk72.3
zombor:bd-bookshelf-cs9.1
zombor:bd-bookshelf-4y3y.3
zombor:bd-bookshelf-4op.5
zombor:bd-bookshelf-80zv.1
zombor:bd-bookshelf-4y3y.6
zombor:bd-bookshelf-cvak
zombor:bd-o3np
zombor:bd-bookshelf-o3np
zombor:bd-bookshelf-4y3y.2
zombor:bd-bookshelf-wg60
zombor:bd-m6x0.4
zombor:bd-bookshelf-ecaf
zombor:bd-uqwl
zombor:bd-bookshelf-8duj
zombor:bd-bookshelf-5gko
zombor:bd-bookshelf-4y3y.1
zombor:bd-bookshelf-wnt7
zombor:bd-bookshelf-hx8i
zombor:bd-bookshelf-jmn7.1
zombor:bd-bookshelf-0cay
zombor:bd-bookshelf-69k4
zombor:bd-bookshelf-rh2k
zombor:bd-bookshelf-fflj
zombor:bd-bookshelf-po6m
zombor:bd-bookshelf-37jn
zombor:bd-bookshelf-xikn
zombor:bd-bookshelf-rgjd
zombor:bd-zz2b
zombor:bd-bookshelf-epxf
zombor:bd-bookshelf-2678
zombor:bd-bookshelf-jmn7.2
zombor:bd-bookshelf-5vc6
zombor:bd-bookshelf-ve3e.6
zombor:bd-bookshelf-kn7x
zombor:bd-bookshelf-9qsi
zombor:bd-bookshelf-pnzo
zombor:bd-bookshelf-yfhm
zombor:bd-bookshelf-kurr
zombor:bd-bookshelf-h8fw
zombor:bd-bookshelf-wzef
zombor:bd-bookshelf-c6bm
zombor:bd-bookshelf-obdm
zombor:bd-bookshelf-x1g6
zombor:bd-bookshelf-2b8a
zombor:bd-bookshelf-hpu4
zombor:bd-bookshelf-gm1p
zombor:bd-bookshelf-624i
zombor:bd-bookshelf-sjpx
zombor:bd-bookshelf-6b8h
zombor:bd-bookshelf-mjbo.3
zombor:bd-bookshelf-7tln
zombor:bd-bookshelf-evw2
zombor:bd-bookshelf-yb5n
zombor:bd-bookshelf-mjbo.2
zombor:bd-bookshelf-m6x0.3
zombor:bd-bookshelf-jmn7.5
zombor:bd-bookshelf-3ehn
zombor:bd-bookshelf-7dfl
zombor:bd-bookshelf-m9gp
zombor:bd-bookshelf-buk6
zombor:bd-bookshelf-53oh
zombor:bd-bookshelf-dn31
zombor:bd-bookshelf-mjbo.8
zombor:bd-bookshelf-6ibb
zombor:bd-bookshelf-mjbo.7
zombor:bd-bookshelf-m6x0.2
zombor:bd-bookshelf-m6x0.1
zombor:bd-bookshelf-ukqt.3
zombor:bd-bookshelf-ukqt.4
zombor:bd-bookshelf-ukqt.2
zombor:bd-bookshelf-mjbo.1
zombor:bd-bookshelf-ukqt.1
zombor:bd-8uqb
zombor:bd-bookshelf-90fa
zombor:bd-bookshelf-8j6l
zombor:bd-review-minors
zombor:bd-bookshelf-pp5v
zombor:bd-bookshelf-8eu.4
zombor:bd-bookshelf-mtxh.5
zombor:bd-bookshelf-mtxh.4
zombor:bd-bookshelf-mtxh.3
zombor:bd-bookshelf-mtxh.2
zombor:bd-bookshelf-mtxh.1
zombor:bd-bookshelf-pwix
zombor:bd-bookshelf-n6gq
zombor:bd-bookshelf-60i0
zombor:bd-bookshelf-135h
zombor:bd-bookshelf-8dbo
zombor:bd-bookshelf-xh7c
zombor:bd-bookshelf-l14e
zombor:bd-bookshelf-dwpw
zombor:bd-bookshelf-1kzh
zombor:bd-bookshelf-9rvz
zombor:bd-bookshelf-3zzc
zombor:bd-bookshelf-2yth.2
zombor:bd-bookshelf-2yth.1
zombor:bd-bookshelf-b9dx
zombor:bd-bookshelf-sp5u
zombor:bd-bookshelf-ve3e.5
zombor:bd-bookshelf-6jrd
zombor:bd-bookshelf-aoem
zombor:bd-bookshelf-eapl
zombor:bd-bookshelf-51tt
zombor:bd-bookshelf-yrz5
zombor:bd-bookshelf-ur0w
zombor:bd-bookshelf-3bxp
zombor:bd-bookshelf-juh7
zombor:poc/go-workflows
zombor:bd-bookshelf-nzv0
zombor:bd-bookshelf-ve3e.3
zombor:bd-bookshelf-ve3e.2
zombor:bd-bookshelf-b32t
zombor:bd-bookshelf-ve3e.1
zombor:bd-bookshelf-vguw.17
zombor:bd-bookshelf-vguw.16
zombor:bd-bookshelf-vguw.14
zombor:bd-bookshelf-vguw.13
zombor:bd-bookshelf-vguw.12
zombor:bd-bookshelf-vguw.10
zombor:bd-bookshelf-vguw.11
zombor:bd-bookshelf-vguw.9
zombor:bd-bookshelf-vguw.8
zombor:bd-bookshelf-vguw.5
zombor:bd-bookshelf-vguw.4
zombor:bd-bookshelf-vguw.3
zombor:bd-bookshelf-vguw.2
zombor:bd-bookshelf-vguw.1
zombor:bd-bookshelf-i32o
zombor:bd-8dbo
zombor:bd-bookshelf-1ho9
zombor:bd-bookshelf-0zpr.5
zombor:bd-bookshelf-0zpr.3
zombor:bd-bookshelf-0zpr.2
zombor:bd-mg0c
zombor:bd-bookshelf-qce9.2
zombor:bd-bookshelf-0zpr.4
zombor:bd-bookshelf-qce9.4
zombor:bd-bookshelf-imcd.3
zombor:bd-bookshelf-2jxl
zombor:bd-bookshelf-imcd.1
zombor:bd-bd4l
zombor:bd-bookshelf-bevu
zombor:bd-bookshelf-imcd.2
zombor:bd-bookshelf-rb97
zombor:bd-fp2r
zombor:bd-uml2
zombor:bd-bookshelf-gphb
zombor:bd-bookshelf-9hcf
zombor:bd-bookshelf-b5pj
zombor:bd-bookshelf-xnm6
zombor:bd-bookshelf-9f97
zombor:bd-bookshelf-50z.3
zombor:bd-bookshelf-50z.4
zombor:bd-50z1-repo-refs
zombor:bd-bookshelf-50z.1
zombor:bd-bookshelf-1xpy
zombor:bd-bookshelf-mn8s
zombor:bd-bookshelf-qce9.1
zombor:bd-bookshelf-9oeo
zombor:bd-bookshelf-idkg
zombor:bd-bookshelf-1nsa
zombor:bd-bookshelf-0zpr.1
zombor:bd-bookshelf-cipr
zombor:bd-bookshelf-n43x
zombor:bd-bookshelf-c9x5
zombor:bd-bookshelf-bukz
zombor:bd-bookshelf-b3s1
zombor:bd-bookshelf-dct5
zombor:bd-bookshelf-r0es
zombor:bd-bookshelf-kfu9
zombor:bd-bookshelf-2359
zombor:bd-bookshelf-qodb
zombor:bd-bookshelf-n2q6
zombor:bd-bookshelf-het5
zombor:bd-bookshelf-2loz
zombor:bd-bookshelf-00yo
zombor:bd-bookshelf-blm4
zombor:bd-bookshelf-3avz
zombor:bd-bookshelf-4op.8
zombor:bd-bookshelf-0j7.16
zombor:bd-bookshelf-v7na
zombor:bd-bookshelf-z83r
zombor:bd-bookshelf-akzq
zombor:bd-bookshelf-6bsv
zombor:bd-bookshelf-0915
zombor:bd-bookshelf-ji8p
zombor:bd-bookshelf-que1
zombor:bd-bookshelf-1axt
zombor:bd-bookshelf-pkbz
zombor:bd-bookshelf-8ggs
zombor:bd-bookshelf-vs3x
zombor:bd-bookshelf-cxlu
zombor:bd-bookshelf-oydh
zombor:bd-bookshelf-10jh
zombor:bd-bookshelf-r2er
zombor:bd-bookshelf-38if
zombor:bd-bookshelf-4c6n
zombor:bd-bookshelf-l9nn
zombor:bd-bookshelf-dwt.8
zombor:bd-bookshelf-w5y.2
zombor:bd-bookshelf-1ozd
zombor:bd-bookshelf-s2fd
zombor:bd-bookshelf-irw
zombor:bd-bookshelf-38y
zombor:bd-bookshelf-9wut.4
zombor:bd-bookshelf-88pi
zombor:bd-bookshelf-pw9
zombor:bd-bookshelf-9wut.3
zombor:bd-bookshelf-u1d
zombor:bd-bookshelf-7wr
zombor:bd-bookshelf-moxf
zombor:bd-bookshelf-9wut.2
zombor:bd-bookshelf-i3z
zombor:bd-bookshelf-s9vp
zombor:bd-bookshelf-nx9x
zombor:bd-bookshelf-fjjl
zombor:bd-bookshelf-s9wm
zombor:bd-bookshelf-9wut.1
zombor:bd-bookshelf-t1ax
zombor:bd-bookshelf-8eu.3
zombor:bd-bookshelf-dwt.5
zombor:bd-bookshelf-j0jh
zombor:bd-bookshelf-5fy
zombor:bd-bookshelf-dwt.9
zombor:bd-bookshelf-4op.4
zombor:bd-bookshelf-8eu.2
zombor:bd-bookshelf-dwt.3
zombor:bd-bookshelf-5j1f
zombor:bd-bookshelf-i8s
zombor:bd-bookshelf-dwt.6
zombor:bd-bookshelf-8eu.1
zombor:bd-bookshelf-pur
zombor:bd-bookshelf-0j7.8
zombor:bd-bookshelf-jgh
zombor:bd-bookshelf-9jt2
zombor:bd-bookshelf-dwt.4
zombor:bd-bookshelf-pts
zombor:bd-bookshelf-nz6
zombor:bd-ful
zombor:bd-bookshelf-3mod
zombor:bd-bookshelf-6xm
zombor:bd-bookshelf-6gj
zombor:bd-bookshelf-ztw
zombor:bd-bookshelf-a56k
zombor:bd-bookshelf-xwh
zombor:bd-93w
zombor:bd-80bn
zombor:bd-bookshelf-7lz
zombor:bd-bookshelf-b4y
zombor:bd-bookshelf-r64
zombor:bd-bookshelf-w8s
zombor:bd-bookshelf-sci
zombor:bd-bookshelf-hj9.2
zombor:bd-bookshelf-91o
zombor:bd-bookshelf-6hh
zombor:bd-bookshelf-ism
zombor:bd-bookshelf-dwt.10
zombor:bd-bookshelf-qm7
zombor:bd-prefix-fix
zombor:bd-bookshelf-abf
zombor:bd-bookshelf-3dz
zombor:bd-bookshelf-xpd.4
zombor:bd-bookshelf-xpd.2.3
zombor:bd-bookshelf-pcz
zombor:bd-bookshelf-e5h
zombor:bd-bookshelf-h6w
zombor:bd-bookshelf-l0m
zombor:bd-bookshelf-xp3
zombor:bd-bookshelf-xpd.3
zombor:bd-bookshelf-xpd.2.5
zombor:bd-bookshelf-adx
zombor:bd-bookshelf-xpd.2.2
zombor:bd-bookshelf-q5k
zombor:bd-bookshelf-6v1
zombor:bd-bookshelf-8cb
zombor:bd-bookshelf-p18
zombor:bd-bookshelf-o0q
zombor:bd-bookshelf-rw5
zombor:bd-bookshelf-z0j
zombor:bd-bookshelf-vtp.10
zombor:bd-bookshelf-fj9
zombor:bd-bookshelf-b9b
zombor:bd-bookshelf-3km
zombor:bd-bookshelf-gch
zombor:bd-bookshelf-as1
zombor:bd-bookshelf-vtp.1
zombor:bd-bookshelf-24j
zombor:bd-bookshelf-a09
zombor:bd-bookshelf-7ev
zombor:bd-bookshelf-krg
zombor:bd-bookshelf-vtp.12
zombor:bd-bookshelf-8jq
zombor:bd-bookshelf-u76
zombor:bd-bookshelf-7fc
zombor:bd-bookshelf-xpd.2.6
zombor:slicing-standard
zombor:bd-bookshelf-xpd.2.7
zombor:bd-bookshelf-28z
zombor:bd-bookshelf-nqx
zombor:bd-bookshelf-9g3.3
zombor:bd-7ev
zombor:bd-bookshelf-nrr
zombor:bd-bookshelf-2se
zombor:bd-bookshelf-hj9.1.1
zombor:bd-bookshelf-hj9.1
zombor:bd-bookshelf-dl3
zombor:bd-bookshelf-17t.9
zombor:bd-bookshelf-17t.4
zombor:bd-bookshelf-2zg
zombor:bd-bookshelf-xpd.2.1
zombor:bd-bookshelf-3ll
zombor:bd-bookshelf-17t.8
zombor:bd-bookshelf-0j7.4
zombor:bd-bookshelf-xpd.2.4
zombor:bd-bookshelf-xpd.1
zombor:bd-bookshelf-ee4
zombor:bd-bookshelf-h77
zombor:bd-bookshelf-466
zombor:bd-bookshelf-0j7.15
zombor:bd-bookshelf-dwt.2
zombor:bd-bookshelf-07i
zombor:bd-bookshelf-0j7.14.4
zombor:bd-bookshelf-rg8
zombor:bd-bookshelf-9g3.2
zombor:bd-bookshelf-17t.7
zombor:bd-bookshelf-17t.2
zombor:bd-bookshelf-17t.5
zombor:bd-bookshelf-17t.6
zombor:bd-bookshelf-17t.3
zombor:bd-bookshelf-17t.1
zombor:bd-bookshelf-o92
zombor:bd-bookshelf-gmp
zombor:bd-bookshelf-0j7.7
zombor:bd-bookshelf-dwt.1
zombor:bd-bookshelf-3u6
zombor:bd-bookshelf-0j7.14.1
zombor:bd-bookshelf-24a.5
zombor:bd-bookshelf-0j7.14.3
zombor:bd-bookshelf-0j7.14.2
zombor:bd-bookshelf-9g3.1
zombor:bd-bookshelf-7pu
zombor:bd-bookshelf-waj.2
zombor:bd-bookshelf-6lc
zombor:bd-bookshelf-um5
zombor:bd-bookshelf-0j7.11
zombor:bd-bookshelf-v0g
zombor:bd-bookshelf-7m0
zombor:bd-bookshelf-4op.7
zombor:bd-bookshelf-ukv.1
zombor:bd-bookshelf-474.3
zombor:bd-bookshelf-3zz
zombor:bd-bookshelf-kb1
zombor:bd-bookshelf-iox
zombor:bd-bookshelf-ahs
zombor:bd-bookshelf-waj.1
zombor:bd-bookshelf-0j7.12
zombor:bd-bookshelf-7ua
zombor:bd-bookshelf-tsa
zombor:bd-bookshelf-474.1
zombor:bd-bookshelf-0j7.10
zombor:bd-bookshelf-w5y.3
zombor:bd-bookshelf-0j7.3
zombor:bd-bookshelf-w3m.9
zombor:bd-bookshelf-w3m.10
zombor:bd-bookshelf-w3m.40
zombor:bd-bookshelf-0j7.13
zombor:bd-bookshelf-w3m.18
zombor:bd-bookshelf-4op.2
zombor:bd-bookshelf-w3m.34
zombor:bd-bookshelf-w3m.27
zombor:bd-bookshelf-ayw
zombor:bd-bookshelf-a86
zombor:bd-bookshelf-6a1
zombor:bd-bookshelf-4op.1
zombor:bd-bookshelf-dkc
zombor:bd-bookshelf-0j7.2
zombor:bd-bookshelf-w3m.24
zombor:bd-bookshelf-e7u
zombor:bd-bookshelf-932
zombor:bd-bookshelf-e69
zombor:bd-bookshelf-w5y.8
zombor:bd-bookshelf-fr5.2
zombor:bd-bookshelf-fnb
zombor:bd-bookshelf-w5y.6
zombor:bd-bookshelf-1pv
zombor:bd-bookshelf-24a.6
zombor:bd-bookshelf-zjb
zombor:bd-bookshelf-dbp
zombor:bd-bookshelf-24a.3
zombor:bd-bookshelf-w5y.5
zombor:bd-bookshelf-0j7.1
zombor:bd-bookshelf-w3m.23
zombor:bd-bookshelf-w3m.26
zombor:bd-bookshelf-w3m.36
zombor:bd-bookshelf-w3m.35
zombor:bd-bookshelf-w3m.39
zombor:bd-bookshelf-w3m.37
zombor:bd-bookshelf-axt.4
zombor:bd-bookshelf-24a.1
zombor:bd-bookshelf-omd
zombor:bd-bookshelf-0gz
zombor:bd-bookshelf-w5y.4
zombor:bd-bookshelf-fu9.3
zombor:bd-bookshelf-ejl.1
zombor:bd-bookshelf-o7z
zombor:bd-bookshelf-c6k
zombor:bd-bookshelf-ejl.3
zombor:bd-bookshelf-tp4
zombor:bd-bookshelf-ejl.2
zombor:bd-bookshelf-fu9.2
zombor:bd-bookshelf-p5w
zombor:bd-bookshelf-fu9.1
zombor:bd-bookshelf-j4f
zombor:bd-bookshelf-axt.3
zombor:bd-bookshelf-w5y.1
zombor:bd-bookshelf-yuh
zombor:bd-bookshelf-nfb
zombor:bd-bookshelf-axt.2
zombor:bd-bookshelf-rna
zombor:bd-bookshelf-2lh
zombor:bd-bookshelf-axt.1
zombor:bd-bookshelf-qqz.5
zombor:bd-bookshelf-s92
zombor:workflow-mergeability-check
zombor:bd-bookshelf-2tc
zombor:bd-bookshelf-8df
zombor:bd-bookshelf-qqz.9
zombor:bd-bookshelf-qqz.4
zombor:bd-bookshelf-qqz.7
zombor:code-style-rules
zombor:ci-drop-mysql-service
zombor:bd-bookshelf-qqz.8
zombor:bd-bookshelf-qqz.11
zombor:bd-bookshelf-qqz.6
zombor:bd-bookshelf-qqz.10
zombor:bd-bookshelf-qqz.3
zombor:bd-bookshelf-qqz.2
No reviewers
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
zombor/pergamum!634
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "bd-bookshelf-w1or"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
WriteComicInfoToCBZininternal/comic/write.go— atomic temp+rename, NETWORK disk guard, CBZ-only guard, 100% test coverage via injectable OS + zip-entry deps (rebuildCBZWith,writeZipWith).ExportComicInfoservice maps book+comic metadata →BookLevelFields+DisplayMetadataand writes the sidecar; curried deps,ErrNotComicsentinel.ExportComicInfoHandlerthin HTTP wrapper:ErrNetworkDisk→ 409,ErrNotCBZ→ 400, JSON 200{"ok":true}/ browser 303 redirect with?comicinfo_exported=1.POST /books/{id}/export-comicinfogated byg.EditMetadata.books_show.htmlkebab menu gains "Export ComicInfo.xml" item for comic book types;book-detail-kebabStimulus controller gainsexportComicInfo(event)with fetch POST, toast success/error feedback, and a 409-specific message for NETWORK disk.Test plan
make test— all unit tests passmake coverage— 100% coverage, zero uncovered statement blocksgolangci-lint run ./internal/comic/... ./internal/books/...— 0 issues{"ok":true}for a valid CBZCloses bead bookshelf-w1or on merge.
🤖 Generated with Claude Code
- Adds WriteComicInfoToCBZ in internal/comic/write.go with atomic temp+rename, NETWORK disk guard, CBZ-only guard, and 100% test coverage via injectable OS and zip-entry deps (rebuildCBZWith, writeZipWith exposed through export_test.go). - ExportComicInfo service (internal/books/export_comicinfo_service.go) maps book+comic metadata → BookLevelFields + DisplayMetadata and calls WriteComicInfoToCBZ; curried deps, ErrNotComic sentinel. - ExportComicInfoHandler thin HTTP wrapper; ErrNetworkDisk→409, ErrNotCBZ→400, JSON 200 {"ok":true} / browser 303 redirect. - Route POST /books/{id}/export-comicinfo gated by g.EditMetadata. - books_show.html kebab menu gains "Export ComicInfo.xml" item for comic book types (ExportComicInfoURL present); book-detail-kebab Stimulus controller gains exportComicInfo(event) with fetch POST, toast feedback, and 409-specific NETWORK disk message. - 100% coverage; curried-function deps; one-Expect-per-It.The export-comicinfo and step-edit handlers were swapped: wire.go passes ExportComicInfoHandler then StepEditHandler, but RegisterRoutes declared the stepEdit parameter first. As a result POST /books/{id}/export-comicinfo was served by the step-edit handler and returned 400 "ids query parameter is required". Reorder the RegisterRoutes parameters (exportComicInfo, stepEdit) to match the wiring call order; the two stub handlers in routes_test.go are identical 200s so the swap is behaviorally inert there (comments updated to stay accurate). Add coverage that would have caught this: - Browser e2e Journey 6e (Ordered): seeds a CBZ + comic_metadata, opens the book-detail kebab, asserts the Export ComicInfo.xml item renders, clicks it, asserts the success toast, and asserts the on-disk ComicInfo.xml was rewritten with the DB Series. Requires real Chromium (Stimulus + real fetch with the page CSRF token + cross-controller toast + archive rewrite) — not reproducible in jsdom or the API e2e tier. Posts a kebab screenshot to the PR. - Vitest: full branch coverage of the exportComicInfo controller method (POST URL, success toast, menu close, 409 NETWORK-disk message, non-409 server error, missing-error-field fallback, non-JSON body, network failure, empty-URL guard, AppDialog-absent alert fallback). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>Security Review — PR #634 (bookshelf-w1or) — ComicInfo.xml Export
Reviewed:
internal/comic/write.go,internal/books/export_comicinfo_service.go,internal/books/export_comicinfo_handler.go,internal/books/routes.go,static/js/controllers/book_detail_kebab_controller.js,templates/pages/books_show.html, diff via API.[MAJOR] internal/books/export_comicinfo_service.go:75 — archive path constructed without library-root traversal guard
archivePath := filepath.Join(libPath, cbzRow.FileSubPath)is passed directly toWriteComicInfoToCBZwithout thestrings.HasPrefix(filepath.Clean(archivePath), cleanedRoot+sep)guard that every other destructive file operation in this codebase applies explicitly.delete_service.go:70-76comments: "Security: verify the resolved path is contained within the library root" and skips any path that escapes.reader_service.go:357-359andreader_handler.go:611-614both apply the same guard before opening a file.attach_service.go:121-123andmove_service.go:465-472also do it.file_sub_pathis written by the library scanner and is not user-controlled in the normal flow, so this is not immediately exploitable. However: (a) the convention in this codebase is explicit and documented; (b) a future code path that rewritesfile_sub_paththrough a less-trusted channel would silently skip the guard here; (c) the archive is overwritten, not just read, making the blast radius of a traversal materially worse than the read paths.Fix: Add before calling
WriteComicInfo:[MINOR] internal/comic/write.go:23 — MaxWriteArchiveBytes comment says "buffer in memory" but writes stream to disk
The var comment reads "caps how large an archive we will fully buffer in memory". This is incorrect.
io.Copystreams from the source zip entry tozip.Writerwhich writes through to the*os.Filetemp file — no in-memory accumulation. The guard correctly limits per-entry uncompressed size to protect against zip-bomb expansion during the copy (a legitimate and necessary check), but the stated reason is wrong and will mislead future maintainers about the actual memory profile.Fix: Change the comment to: "caps the uncompressed size of any single entry copied during archive rebuild, guarding against zip-bomb expansion."
[MINOR] internal/books/export_comicinfo_handler.go:24 vs :80 — doc comment says 204, code returns 200
The handler doc comment says "JSON clients (Accept: application/json): 204 No Content" but the implementation calls
w.WriteHeader(http.StatusOK)(200) and writes a JSON body{"ok":true}. The handler test asserts 200. Either the comment should say 200, or the implementation should be changed to 204 (omit body, usehttp.StatusNoContent). As-is the doc is wrong and the JS client checksresp.ok(which passes for any 2xx), so there is no functional breakage — but it will confuse future readers.Fix: Align: either update the doc comment to say "200 OK with
{\"ok\":true}" or change the implementation tow.WriteHeader(http.StatusNoContent)and drop the JSON body.Items reviewed and found clean
Per-user library-access auth:
checkBookAccess(ctx, bookID, userID)is called in the handler beforeexport()is invoked. The wiring inwire.go:783-802passes the samecheckBookAccessused across all other mutation paths. The route registration atroutes.go:116gates the handler behindg.EditMetadata(PermissionEditMetadata). The access check returnsmiddleware.ErrNotFoundon miss (no library-ID leak). Correct.CSRF:
middleware.CSRFis applied globally inapp.go:583to the entire handler chain. The JSexportComicInfo()method sendsX-CSRF-Token: csrfToken()(double-submit cookie pattern) on every fetch. Covered.DISK_TYPE guard:
WriteComicInfoToCBZchecksstrings.ToUpper(diskType) == "NETWORK"(case-insensitive, tested) and returnsErrNetworkDiskbefore touching the filesystem. Handler maps this to HTTP 409. Correct.Atomic write: temp file created in same directory as archive →
writeZip→closeFile→os.Rename. Temp is cleaned up onwriteErr,closeErr, orrenamefailure. Original archive is only replaced on a successful rename. Correct POSIX atomic pattern.ZIP handling / zip-slip on write:
writeZipWithcopies entryFileHeadervalues verbatim (preserving names/paths). This is a write path — the entry names are written into the new temp archive, not extracted to disk. No zip-slip risk exists on the write side. Entry names from the existing archive in the library are server-trusted.Zip-bomb / entry size cap:
MaxWriteArchiveBytes(200 MB) is checked againstf.UncompressedSize64per entry beforeio.Copy. Entries exceeding the cap abort the rebuild with an error.XML generation / injection:
xml.NewEncoderwith a struct ofstring-typed fields automatically escapes<,>,&,"— no raw injection risk.xml.Headerprefix is correct.Error propagation in zip.Writer:
CreateHeader,fw.Write, andio.Copyerrors are suppressed with//nolint:errcheckbecausezip.Writerrecords the first write error internally and surfaces it atzw.Close(), which is the correctly-checked return value. This is the idiomatic Go pattern forzip.Writerand is sound here.No user-supplied path:
archivePathis constructed entirely from DB-sourced values (libPathfromGetLibraryPath,FileSubPathfromGetPrimaryCBZFile), neither of which originates from the HTTP request.Permission gate comment accuracy: Comment on
ExportComicInfoHandlercorrectly documentsg.EditMetadataas the gate (set at the mux level).REVIEW VERDICT: 0 blocker, 1 major, 2 minor
CODE REVIEW: NOT APPROVED
Phase 0: DEMO Verification
No DEMO block found in the PR body or bead comments. The PR has a test-plan checklist but no executable shell commands for me to re-run. Per review policy this is NOT APPROVED — "No DEMO block provided."
I continued through phases 1 and 2 to give actionable feedback regardless.
Phase 1 + 2: Findings
[MAJOR] internal/books/export_comicinfo_service.go:21 — struct-of-funcs banned by project conventions
ExportComicInfoDepsis an explicit struct-of-funcs, whichproject-conventions.mdbans: "No struct-of-funcs shortcut, no interface escape hatch. If a function ends up needing five func args, that's a signal to split it; if it genuinely needs them, write the signature out." The service has 5 dep-funcs + 1 string field; writeExportComicInfo(getPrimaryCBZFile, getLibraryPath, getComicMetadata, getBookMetadata func(...) ..., writeComicInfo func(...) ..., diskType string) func(...)as individual curried arguments.[MAJOR] internal/books/export_comicinfo_service.go:50-54 + export_comicinfo_handler.go:66 — CBR/RAR case yields 500, not 400
When a book's primary CBX file has
archive_type = 'RAR'(i.e. CBR), the service returnsErrNotComic(line 54) — notcomic.ErrNotCBZ. The handler only checkserrors.Is(err, comic.ErrNotCBZ)(line 66) to map to 400;ErrNotComicfalls through to the genericreturn errpath, which the middleware translates to 500. The PR description and test plan both claim "returns 400 when archive is RAR/CBR" but this is incorrect. The handler test for "ErrNotCBZ → 400" (line 157) tests a case that cannot arise from the real service. Fix: adderrors.Is(err, books.ErrNotComic)to the handler's error-mapping block and map it tomiddleware.ErrValidation, or have the service wrap withcomic.ErrNotCBZfor the non-ZIP archive_type case.[MINOR] internal/comic/write.go:79 —
VolumeXML field never populated despiteDisplayMetadata.VolumeNumberexistingcomicInfoXMLWrite.Volumeis declared (line 79) and the<Volume>element in ComicInfo.xml represents the numeric volume identifier.DisplayMetadatahasVolumeNumber *int32(comic.go:43) butmarshalComicInfonever setsinfo.Volume. A round-trip export will silently drop the volume number. Note:VolumeNamecorrectly maps to<Series>(per the ComicInfo spec); the missing field isVolumeNumber→<Volume>. Add:if m.VolumeNumber != nil { info.Volume = fmt.Sprintf("%d", *m.VolumeNumber) }.[MINOR] internal/books/wire.go:783-795 — misindented ExportComicInfoHandler block
The
ExportComicInfoHandler(...)invocation and itsExportComicInfo(ExportComicInfoDeps{...})inner call are indented incorrectly relative to the surroundingRegisterRoutesargument list. The args toExportComicInfoHandlerstart at column 2 instead of matching the tab depth of sibling arguments. Minor cosmetic but noticeable against the rest of the file.[MINOR] internal/books/export_comicinfo_handler.go:85-88 — JSON success response is 200 with body, doc comment says 204
The handler doc comment (line 26) says "204 No Content" for JSON clients but the code writes
http.StatusOK(200) with{"ok":true}. Either fix the code to use 204 (and remove the body) or fix the comment. Minor inconsistency.Summary
REVIEW VERDICT: 0 blocker, 2 major, 3 minor
The RAR→500 bug (major #2) is a real user-facing defect: a CBR comic triggers a 500 instead of a clear 400 "not writable" error. The struct-of-funcs (major #1) is a convention violation. Both need to be fixed before merge.
Rendered UI — book-detail kebab with Export ComicInfo.xml
From browser e2e Journey 6e (real Chromium, comic detail page, menu open). The new item is styled identically to its siblings and sits above the destructive Delete action.
MAJORs: - Convert ExportComicInfoDeps struct-of-funcs to curried individual func args (project convention: struct-of-funcs banned in domain code) - Add library-root path-traversal guard before WriteComicInfoToCBZ; unit spec asserts escaping FileSubPath returns ErrNotFound - Map ErrNotComic -> 400 Bad Request in handler; add handler test for RAR path MINORs: - Fix misleading MaxWriteArchiveBytes comment (streams, does not buffer) - Populate Volume XML field from m.VolumeNumber in marshalComicInfo; add VolumeNumber field to DisplayMetadata + service.Get; add write_test + service_test coverage (comic package now 100%) - Fix inconsistent indentation in wire.go ExportComicInfoHandler block - Align handler doc comment to actual 200 OK + {"ok":true} response Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>Pull request closed