diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index e1ac19d..986aed8 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v4
with:
- go-version: '1.20'
+ go-version: '1.24'
- name: Install dependencies
run: go mod download
diff --git a/go.mod b/go.mod
index f50c273..9faaf37 100644
--- a/go.mod
+++ b/go.mod
@@ -1,11 +1,17 @@
module github.com/asticode/go-astisub
-go 1.13
+go 1.24.0
require (
- github.com/asticode/go-astikit v0.20.0
- github.com/asticode/go-astits v1.8.0
+ github.com/asticode/go-astikit v0.58.0
+ github.com/asticode/go-astits v1.15.0
github.com/stretchr/testify v1.4.0
- golang.org/x/net v0.0.0-20200904194848-62affa334b73
- golang.org/x/text v0.3.2
+ golang.org/x/net v0.49.0
+ golang.org/x/text v0.33.0
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.0 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ gopkg.in/yaml.v2 v2.2.2 // indirect
)
diff --git a/go.sum b/go.sum
index dea5cec..3b32195 100644
--- a/go.sum
+++ b/go.sum
@@ -1,27 +1,151 @@
-github.com/asticode/go-astikit v0.20.0 h1:+7N+J4E4lWx2QOkRdOf6DafWJMv6O4RRfgClwQokrH8=
-github.com/asticode/go-astikit v0.20.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
-github.com/asticode/go-astits v1.8.0 h1:rf6aiiGn/QhlFjNON1n5plqF3Fs025XLUwiQ0NB6oZg=
-github.com/asticode/go-astits v1.8.0/go.mod h1:DkOWmBNQpnr9mv24KfZjq4JawCFX1FCqjLVGvO0DygQ=
+github.com/asticode/go-astikit v0.30.0/go.mod h1:h4ly7idim1tNhaVkdVBeXQZEE3L0xblP7fCWbgwipF0=
+github.com/asticode/go-astikit v0.58.0 h1:WXNpaxCPNFReikHiXvzyDv49NpV/GMD6PV80iem6WGo=
+github.com/asticode/go-astikit v0.58.0/go.mod h1:fV43j20UZYfXzP9oBn33udkvCvDvCDhzjVqoLFuuYZE=
+github.com/asticode/go-astits v1.15.0 h1:yRyCiUc8Jj4F7clt2GDxHghMpWuFL5rkaLuGUd2/0J4=
+github.com/asticode/go-astits v1.15.0/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
-golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
+golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
+golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
+golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
+golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
+golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
+golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
+golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
+golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
+golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
+golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
+golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
+golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
+golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
+golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
+golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
+golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
+golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
+golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
+golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
+golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
+golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
+golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
+golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
+golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
+golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
+golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
+golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
+golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
+golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
+golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
+golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
+golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
+golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
+golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
+golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
+golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
+golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
+golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
+golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
+golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
+golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
+golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
+golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
+golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
+golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
+golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
+golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
+golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
+golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
+golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
+golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
+golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
+golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
+golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
+golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
+golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
+golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
diff --git a/srt.go b/srt.go
index fbf0daf..59e4f60 100644
--- a/srt.go
+++ b/srt.go
@@ -8,6 +8,7 @@ import (
"time"
"unicode/utf8"
+ "github.com/asticode/go-astikit"
"golang.org/x/net/html"
)
@@ -223,49 +224,60 @@ func (s Subtitles) WriteToSRT(o io.Writer) (err error) {
return
}
+ // Init chainer
+ c := astikit.NewWriteChainer(o)
+
// Add BOM header
- var c []byte
- c = append(c, BytesBOM...)
+ if _, err = c.Write(astikit.WriteWithLabel("bom", BytesBOM)); err != nil {
+ return
+ }
// Loop through subtitles
for k, v := range s.Items {
// Add time boundaries
- c = append(c, []byte(strconv.Itoa(k+1))...)
- c = append(c, bytesLineSeparator...)
- c = append(c, []byte(formatDurationSRT(v.StartAt))...)
- c = append(c, bytesSRTTimeBoundariesSeparator...)
- c = append(c, []byte(formatDurationSRT(v.EndAt))...)
- c = append(c, bytesLineSeparator...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("index", []byte(strconv.Itoa(k+1))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ astikit.WriteWithLabel("start at", []byte(formatDurationSRT(v.StartAt))),
+ astikit.WriteWithLabel("time boundaries separator", bytesSRTTimeBoundariesSeparator),
+ astikit.WriteWithLabel("end at", []byte(formatDurationSRT(v.EndAt))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
// Loop through lines
for _, l := range v.Lines {
- c = append(c, []byte(l.srtBytes())...)
+ if err = l.writeSRT(c); err != nil {
+ err = fmt.Errorf("astisub: writing line item failed: %w", err)
+ return
+ }
}
// Add new line
- c = append(c, bytesLineSeparator...)
- }
-
- // Remove last new line
- c = c[:len(c)-1]
-
- // Write
- if _, err = o.Write(c); err != nil {
- err = fmt.Errorf("astisub: writing failed: %w", err)
- return
+ if k < len(s.Items)-1 {
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
+ }
+ }
}
return
}
-func (l Line) srtBytes() (c []byte) {
+func (l Line) writeSRT(c *astikit.WriteChainer) (err error) {
for _, li := range l.Items {
- c = append(c, li.srtBytes()...)
+ if err = li.writeSRT(c); err != nil {
+ err = fmt.Errorf("astisub: writing line item failed: %w", err)
+ return
+ }
+ }
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
}
- c = append(c, bytesLineSeparator...)
return
}
-func (li LineItem) srtBytes() (c []byte) {
+func (li LineItem) writeSRT(c *astikit.WriteChainer) (err error) {
// Get color
var color string
if li.InlineStyle != nil && li.InlineStyle.SRTColor != nil {
@@ -283,34 +295,20 @@ func (li LineItem) srtBytes() (c []byte) {
pos = li.InlineStyle.SRTPosition
}
- // Append
- if color != "" {
- c = append(c, []byte("")...)
- }
- if b {
- c = append(c, []byte("")...)
- }
- if i {
- c = append(c, []byte("")...)
- }
- if u {
- c = append(c, []byte("")...)
- }
- if pos != 0 {
- c = append(c, []byte(fmt.Sprintf(`{\an%d}`, pos))...)
- }
- c = append(c, []byte(escapeHTML(li.Text))...)
- if u {
- c = append(c, []byte("")...)
- }
- if i {
- c = append(c, []byte("")...)
- }
- if b {
- c = append(c, []byte("")...)
- }
- if color != "" {
- c = append(c, []byte("")...)
+ // Write
+ if _, err = c.Write(
+ astikit.WriteWithCondition("font color", []byte(""), color != ""),
+ astikit.WriteWithCondition("bold", []byte(""), b),
+ astikit.WriteWithCondition("italics", []byte(""), i),
+ astikit.WriteWithCondition("underline", []byte(""), u),
+ astikit.WriteWithCondition("position", []byte(fmt.Sprintf(`{\an%d}`, pos)), pos != 0),
+ astikit.WriteWithLabel("text", []byte(escapeHTML(li.Text))),
+ astikit.WriteWithCondition("underline close", []byte(""), u),
+ astikit.WriteWithCondition("italics close", []byte(""), i),
+ astikit.WriteWithCondition("bold close", []byte(""), b),
+ astikit.WriteWithCondition("font close", []byte(""), color != ""),
+ ); err != nil {
+ return
}
return
}
diff --git a/srt_test.go b/srt_test.go
index 0c57597..e605c25 100644
--- a/srt_test.go
+++ b/srt_test.go
@@ -171,3 +171,16 @@ func TestSRTParseDuration(t *testing.T) {
assert.Equal(t, 5*time.Second+985*time.Millisecond, s.Items[1].EndAt)
assert.Equal(t, "Duration without colon milliseconds", s.Items[1].Lines[0].String())
}
+
+func BenchmarkWriteToSRT(b *testing.B) {
+ s, err := astisub.OpenFile("./testdata/example-in.srt")
+ if err != nil {
+ b.Fatal(err)
+ }
+ w := &bytes.Buffer{}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ w.Reset()
+ s.WriteToSRT(w)
+ }
+}
diff --git a/ssa.go b/ssa.go
index 228ab2a..5bc8ad0 100644
--- a/ssa.go
+++ b/ssa.go
@@ -409,57 +409,157 @@ func (b *ssaScriptInfo) metadata() *Metadata {
}
}
-// bytes returns the block as bytes
-func (b *ssaScriptInfo) bytes() (o []byte) {
- o = []byte("[Script Info]")
- o = append(o, bytesLineSeparator...)
- for _, c := range b.comments {
- o = appendStringToBytesWithNewLine(o, "; "+c)
+// write writes the block to the writer
+func (b *ssaScriptInfo) write(c *astikit.WriteChainer) (err error) {
+ if _, err = c.Write(astikit.WriteWithLabel("script info header", []byte("[Script Info]"))); err != nil {
+ return
+ }
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
+ }
+ for _, comment := range b.comments {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("comment start", []byte("; ")),
+ astikit.WriteWithLabel("comment text", []byte(comment)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.collisions) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameCollisions+": "+b.collisions)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("collisions label", []byte(ssaScriptInfoNameCollisions+": ")),
+ astikit.WriteWithLabel("collisions", []byte(b.collisions)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.originalEditing) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameOriginalEditing+": "+b.originalEditing)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("original editing label", []byte(ssaScriptInfoNameOriginalEditing+": ")),
+ astikit.WriteWithLabel("original editing", []byte(b.originalEditing)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.originalScript) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameOriginalScript+": "+b.originalScript)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("original script label", []byte(ssaScriptInfoNameOriginalScript+": ")),
+ astikit.WriteWithLabel("original script", []byte(b.originalScript)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.originalTiming) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameOriginalTiming+": "+b.originalTiming)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("original timing label", []byte(ssaScriptInfoNameOriginalTiming+": ")),
+ astikit.WriteWithLabel("original timing", []byte(b.originalTiming)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.originalTranslation) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameOriginalTranslation+": "+b.originalTranslation)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("original translation label", []byte(ssaScriptInfoNameOriginalTranslation+": ")),
+ astikit.WriteWithLabel("original translation", []byte(b.originalTranslation)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if b.playDepth != nil {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNamePlayDepth+": "+strconv.Itoa(*b.playDepth))
+ if _, err = c.Write(
+ astikit.WriteWithLabel("play depth label", []byte(ssaScriptInfoNamePlayDepth+": ")),
+ astikit.WriteWithLabel("play depth", []byte(strconv.Itoa(*b.playDepth))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if b.playResX != nil {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNamePlayResX+": "+strconv.Itoa(*b.playResX))
+ if _, err = c.Write(
+ astikit.WriteWithLabel("play res x label", []byte(ssaScriptInfoNamePlayResX+": ")),
+ astikit.WriteWithLabel("play res x", []byte(strconv.Itoa(*b.playResX))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if b.playResY != nil {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNamePlayResY+": "+strconv.Itoa(*b.playResY))
+ if _, err = c.Write(
+ astikit.WriteWithLabel("play res y label", []byte(ssaScriptInfoNamePlayResY+": ")),
+ astikit.WriteWithLabel("play res y", []byte(strconv.Itoa(*b.playResY))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.scriptType) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameScriptType+": "+b.scriptType)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("script type label", []byte(ssaScriptInfoNameScriptType+": ")),
+ astikit.WriteWithLabel("script type", []byte(b.scriptType)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.scriptUpdatedBy) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameScriptUpdatedBy+": "+b.scriptUpdatedBy)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("script updated by label", []byte(ssaScriptInfoNameScriptUpdatedBy+": ")),
+ astikit.WriteWithLabel("script updated by", []byte(b.scriptUpdatedBy)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.synchPoint) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameSynchPoint+": "+b.synchPoint)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("synch point label", []byte(ssaScriptInfoNameSynchPoint+": ")),
+ astikit.WriteWithLabel("synch point", []byte(b.synchPoint)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if b.timer != nil {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameTimer+": "+strings.Replace(strconv.FormatFloat(*b.timer, 'f', -1, 64), ".", ",", -1))
+ if _, err = c.Write(
+ astikit.WriteWithLabel("timer label", []byte(ssaScriptInfoNameTimer+": ")),
+ astikit.WriteWithLabel("timer", []byte(strings.Replace(strconv.FormatFloat(*b.timer, 'f', -1, 64), ".", ",", -1))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.title) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameTitle+": "+b.title)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("title label", []byte(ssaScriptInfoNameTitle+": ")),
+ astikit.WriteWithLabel("title", []byte(b.title)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.updateDetails) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameUpdateDetails+": "+b.updateDetails)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("update details label", []byte(ssaScriptInfoNameUpdateDetails+": ")),
+ astikit.WriteWithLabel("update details", []byte(b.updateDetails)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
if len(b.wrapStyle) > 0 {
- o = appendStringToBytesWithNewLine(o, ssaScriptInfoNameWrapStyle+": "+b.wrapStyle)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("wrap style label", []byte(ssaScriptInfoNameWrapStyle+": ")),
+ astikit.WriteWithLabel("wrap style", []byte(b.wrapStyle)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
return
}
@@ -1173,9 +1273,12 @@ func (s Subtitles) WriteToSSA(o io.Writer) (err error) {
return
}
+ // Init chainer
+ c := astikit.NewWriteChainer(o)
+
// Write Script Info block
var si = newSSAScriptInfo(s.Metadata)
- if _, err = o.Write(si.bytes()); err != nil {
+ if err = si.write(c); err != nil {
err = fmt.Errorf("astisub: writing script info block failed: %w", err)
return
}
@@ -1185,9 +1288,12 @@ func (s Subtitles) WriteToSSA(o io.Writer) (err error) {
// Write Styles block
if len(s.Styles) > 0 {
// Header
- var b = []byte("\n[V4 Styles]\n")
+ var header = "\n[V4 Styles]\n"
if v4plus {
- b = []byte("\n[V4+ Styles]\n")
+ header = "\n[V4+ Styles]\n"
+ }
+ if _, err = c.Write(astikit.WriteWithLabel("styles header", []byte(header))); err != nil {
+ return
}
// Format
@@ -1201,25 +1307,33 @@ func (s Subtitles) WriteToSSA(o io.Writer) (err error) {
styles[ss.name] = ss
styleNames = append(styleNames, ss.name)
}
- b = append(b, []byte("Format: "+strings.Join(format, ", ")+"\n")...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("styles format label", []byte("Format: ")),
+ astikit.WriteWithLabel("styles format", []byte(strings.Join(format, ", "))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
// Styles
sort.Strings(styleNames)
for _, n := range styleNames {
- b = append(b, []byte("Style: "+styles[n].string(format)+"\n")...)
- }
-
- // Write
- if _, err = o.Write(b); err != nil {
- err = fmt.Errorf("astisub: writing styles block failed: %w", err)
- return
+ if _, err = c.Write(
+ astikit.WriteWithLabel("style label", []byte("Style: ")),
+ astikit.WriteWithLabel("style", []byte(styles[n].string(format))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
}
// Write Events block
if len(s.Items) > 0 {
// Header
- var b = []byte("\n[Events]\n")
+ if _, err = c.Write(astikit.WriteWithLabel("events header", []byte("\n[Events]\n"))); err != nil {
+ return
+ }
// Format
// We need to declare those 9 columns here otherwise VLC doesn't display subtitles properly
@@ -1242,17 +1356,23 @@ func (s Subtitles) WriteToSSA(o io.Writer) (err error) {
events = append(events, newSSAEventFromItem(*i))
}
format = append(format, ssaEventFormatNameText)
- b = append(b, []byte("Format: "+strings.Join(format, ", ")+"\n")...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("events format label", []byte("Format: ")),
+ astikit.WriteWithLabel("events format", []byte(strings.Join(format, ", "))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
// Styles
for _, e := range events {
- b = append(b, []byte(ssaEventCategoryDialogue+": "+e.string(format)+"\n")...)
- }
-
- // Write
- if _, err = o.Write(b); err != nil {
- err = fmt.Errorf("astisub: writing events block failed: %w", err)
- return
+ if _, err = c.Write(
+ astikit.WriteWithLabel("event dialogue label", []byte(ssaEventCategoryDialogue+": ")),
+ astikit.WriteWithLabel("event dialogue", []byte(e.string(format))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
}
}
return
diff --git a/stl.go b/stl.go
index 14e05eb..dcf7d4a 100644
--- a/stl.go
+++ b/stl.go
@@ -969,18 +969,19 @@ func (s Subtitles) WriteToSTL(o io.Writer) (err error) {
return
}
+ // Init chainer
+ c := astikit.NewWriteChainer(o)
+
// Write GSI block
var g = newGSIBlock(s)
- if _, err = o.Write(g.bytes()); err != nil {
- err = fmt.Errorf("astisub: writing gsi block failed: %w", err)
+ if _, err = c.Write(astikit.WriteWithLabel("gsi block", g.bytes())); err != nil {
return
}
// Loop through items
for idx, item := range s.Items {
// Write tti block
- if _, err = o.Write(newTTIBlock(item, idx+1, g.displayStandardCode).bytes(g)); err != nil {
- err = fmt.Errorf("astisub: writing tti block #%d failed: %w", idx+1, err)
+ if _, err = c.Write(astikit.WriteWithLabel("tti block", newTTIBlock(item, idx+1, g.displayStandardCode).bytes(g))); err != nil {
return
}
}
diff --git a/subtitles.go b/subtitles.go
index ea1e853..07c2969 100644
--- a/subtitles.go
+++ b/subtitles.go
@@ -9,6 +9,7 @@ import (
"math"
"os"
"path/filepath"
+ "reflect"
"sort"
"strconv"
"strings"
@@ -1000,6 +1001,76 @@ func (s *Subtitles) Order() {
})
}
+// ClipFrom clip items from input time
+func (s *Subtitles) ClipFrom(cf time.Duration) {
+ newIndex := 0
+ var items []*Item
+ for index := 0; index < len(s.Items); index++ {
+ s.Items[index].StartAt -= cf
+ s.Items[index].EndAt -= cf
+ s.Items[index].Index = newIndex
+ if s.Items[index].StartAt < 0 {
+ s.Items[index].StartAt = 0
+ }
+ if s.Items[index].EndAt > 0 {
+ items = append(items, s.Items[index])
+ }
+ }
+ s.Items = items
+}
+
+func copy(source interface{}, destin interface{}) {
+ x := reflect.ValueOf(source)
+ if x.Kind() == reflect.Ptr {
+ starX := x.Elem()
+ y := reflect.New(starX.Type())
+ starY := y.Elem()
+ starY.Set(starX)
+ reflect.ValueOf(destin).Elem().Set(y.Elem())
+ }
+}
+
+// Clone subtitles
+func (s *Subtitles) Clone() *Subtitles {
+ sub := &Subtitles{}
+ copy(s.Metadata, sub.Metadata)
+ for k, r := range s.Regions {
+ copy(r, sub.Regions[k])
+ }
+ for k, r := range s.Styles {
+ copy(r, sub.Styles[k])
+ }
+ for i := 0; i < len(s.Items); i++ {
+ n := &Item{}
+ copy(s.Items[i], n)
+ sub.Items = append(sub.Items, n)
+ }
+ return sub
+}
+
+// ClipFrom clip items until input time
+func (s *Subtitles) ClipTo(ct time.Duration) {
+ lastIndex := 0
+ for index := 0; index < len(s.Items); index++ {
+ lastIndex = index
+ if s.Items[index].StartAt > ct {
+ break
+ }
+ if s.Items[index].EndAt > ct {
+ s.Items[index].EndAt = ct
+ break
+ }
+ }
+ s.Items = s.Items[:lastIndex+1]
+}
+
+// FixIndex fix item index
+func (s *Subtitles) FixIndex() {
+ for i := 0; i < len(s.Items); i++ {
+ s.Items[i].Index = i + 1
+ }
+}
+
// RemoveStyling removes the styling from the subtitles
func (s *Subtitles) RemoveStyling() {
s.Regions = map[string]*Region{}
diff --git a/subtitles_test.go b/subtitles_test.go
index 749105d..d2b8fc0 100644
--- a/subtitles_test.go
+++ b/subtitles_test.go
@@ -280,6 +280,32 @@ func TestSubtitles_RemoveStyling(t *testing.T) {
}, s)
}
+func TestSubtitles_FixIndex(t *testing.T) {
+ var s = mockSubtitles()
+ s.FixIndex()
+ for i := 0; i < len(s.Items); i++ {
+ assert.Equal(t, i+1, s.Items[i].Index)
+ }
+}
+
+func TestSubtitles_ClipTo(t *testing.T) {
+ var s = mockSubtitles()
+ s.ClipTo(2 * time.Second)
+ assert.Equal(t, 1, len(s.Items))
+ assert.Equal(t, 1*time.Second, s.Items[0].StartAt)
+ assert.Equal(t, 2*time.Second, s.Items[0].EndAt)
+}
+
+func TestSubtitles_ClipFrom(t *testing.T) {
+ var s = mockSubtitles()
+ s.ClipFrom(2 * time.Second)
+ assert.Equal(t, 2, len(s.Items))
+ assert.Equal(t, 0*time.Second, s.Items[0].StartAt)
+ assert.Equal(t, 1*time.Second, s.Items[0].EndAt)
+ assert.Equal(t, 1*time.Second, s.Items[1].StartAt)
+ assert.Equal(t, 5*time.Second, s.Items[1].EndAt)
+}
+
func TestSubtitles_ApplyLinearCorrection(t *testing.T) {
s := &astisub.Subtitles{Items: []*astisub.Item{
{
diff --git a/webvtt.go b/webvtt.go
index 8dfd4ca..2f0aecb 100644
--- a/webvtt.go
+++ b/webvtt.go
@@ -13,6 +13,8 @@ import (
"unicode/utf8"
"golang.org/x/net/html"
+
+ "github.com/asticode/go-astikit"
)
// https://www.w3.org/TR/webvtt1/
@@ -412,11 +414,12 @@ func parseTextWebVTT(i string, sa *StyleAttributes) (o Line) {
}
// Push the tag to stack
- sa.WebVTTTags = append(sa.WebVTTTags, WebVTTTag{
+ tag := WebVTTTag{
Name: tagName,
Classes: classes,
Annotation: annotation,
- })
+ }
+ sa.WebVTTTags = append(sa.WebVTTTags, tag)
}
case html.TextToken:
@@ -424,7 +427,9 @@ func parseTextWebVTT(i string, sa *StyleAttributes) (o Line) {
var styleAttributes *StyleAttributes
if len(sa.WebVTTTags) > 0 {
tags := make([]WebVTTTag, len(sa.WebVTTTags))
- copy(tags, sa.WebVTTTags)
+ for i, t := range sa.WebVTTTags {
+ tags[i] = t
+ }
styleAttributes = &StyleAttributes{
WebVTTTags: tags,
}
@@ -490,6 +495,7 @@ func formatDurationWebVTT(i time.Duration) string {
}
// WriteToWebVTT writes subtitles in .vtt format
+// if set true in second args write index as item index
func (s Subtitles) WriteToWebVTT(o io.Writer) (err error) {
// Do not write anything if no subtitles
if len(s.Items) == 0 {
@@ -497,19 +503,29 @@ func (s Subtitles) WriteToWebVTT(o io.Writer) (err error) {
return
}
+ // Init chainer
+ c := astikit.NewWriteChainer(o)
+
// Add header
- var c []byte
- c = append(c, []byte("WEBVTT")...)
+ if _, err = c.Write(astikit.WriteWithLabel("header", []byte("WEBVTT"))); err != nil {
+ return
+ }
// Write X-TIMESTAMP-MAP if set
if s.Metadata != nil {
webVTTTimestampMap := s.Metadata.WebVTTTimestampMap
if webVTTTimestampMap != nil {
- c = append(c, []byte("\n")...)
- c = append(c, []byte(webVTTTimestampMap.String())...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("newline", []byte("\n")),
+ astikit.WriteWithLabel("timestamp map", []byte(webVTTTimestampMap.String())),
+ ); err != nil {
+ return
+ }
}
}
- c = append(c, []byte("\n\n")...)
+ if _, err = c.Write(astikit.WriteWithLabel("newline", []byte("\n\n"))); err != nil {
+ return
+ }
var style []string
for _, s := range s.Styles {
@@ -519,7 +535,9 @@ func (s Subtitles) WriteToWebVTT(o io.Writer) (err error) {
}
if len(style) > 0 {
- c = append(c, []byte(fmt.Sprintf("STYLE\n%s\n\n", strings.Join(style, "\n")))...)
+ if _, err = c.Write(astikit.WriteWithLabel("style", []byte(fmt.Sprintf("STYLE\n%s\n\n", strings.Join(style, "\n"))))); err != nil {
+ return
+ }
}
// Add regions
@@ -530,137 +548,237 @@ func (s Subtitles) WriteToWebVTT(o io.Writer) (err error) {
sort.Strings(k)
for _, id := range k {
- c = append(c, []byte("Region: id="+s.Regions[id].ID)...)
- if s.Regions[id].InlineStyle.WebVTTLines != 0 {
- c = append(c, bytesSpace...)
- c = append(c, []byte("lines="+strconv.Itoa(s.Regions[id].InlineStyle.WebVTTLines))...)
- } else if s.Regions[id].Style != nil && s.Regions[id].Style.InlineStyle != nil && s.Regions[id].Style.InlineStyle.WebVTTLines != 0 {
- c = append(c, bytesSpace...)
- c = append(c, []byte("lines="+strconv.Itoa(s.Regions[id].Style.InlineStyle.WebVTTLines))...)
- }
- if s.Regions[id].InlineStyle.WebVTTRegionAnchor != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("regionanchor="+s.Regions[id].InlineStyle.WebVTTRegionAnchor)...)
- } else if s.Regions[id].Style != nil && s.Regions[id].Style.InlineStyle != nil && s.Regions[id].Style.InlineStyle.WebVTTRegionAnchor != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("regionanchor="+s.Regions[id].Style.InlineStyle.WebVTTRegionAnchor)...)
- }
- if s.Regions[id].InlineStyle.WebVTTScroll != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("scroll="+s.Regions[id].InlineStyle.WebVTTScroll)...)
- } else if s.Regions[id].Style != nil && s.Regions[id].Style.InlineStyle != nil && s.Regions[id].Style.InlineStyle.WebVTTScroll != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("scroll="+s.Regions[id].Style.InlineStyle.WebVTTScroll)...)
- }
- if s.Regions[id].InlineStyle.WebVTTViewportAnchor != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("viewportanchor="+s.Regions[id].InlineStyle.WebVTTViewportAnchor)...)
- } else if s.Regions[id].Style != nil && s.Regions[id].Style.InlineStyle != nil && s.Regions[id].Style.InlineStyle.WebVTTViewportAnchor != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("viewportanchor="+s.Regions[id].Style.InlineStyle.WebVTTViewportAnchor)...)
- }
- if s.Regions[id].InlineStyle.WebVTTWidth != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("width="+s.Regions[id].InlineStyle.WebVTTWidth)...)
- } else if s.Regions[id].Style != nil && s.Regions[id].Style.InlineStyle != nil && s.Regions[id].Style.InlineStyle.WebVTTWidth != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("width="+s.Regions[id].Style.InlineStyle.WebVTTWidth)...)
- }
- c = append(c, bytesLineSeparator...)
+ var r = s.Regions[id]
+ if _, err = c.Write(astikit.WriteWithLabel("region id", []byte("Region: id="+r.ID))); err != nil {
+ return
+ }
+
+ // Lines
+ lines := r.InlineStyle.WebVTTLines
+ if lines == 0 && r.Style != nil && r.Style.InlineStyle != nil {
+ lines = r.Style.InlineStyle.WebVTTLines
+ }
+ if lines != 0 {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("lines", []byte("lines="+strconv.Itoa(lines))),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Region anchor
+ ra := r.InlineStyle.WebVTTRegionAnchor
+ if ra == "" && r.Style != nil && r.Style.InlineStyle != nil {
+ ra = r.Style.InlineStyle.WebVTTRegionAnchor
+ }
+ if ra != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("regionanchor", []byte("regionanchor="+ra)),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Scroll
+ scroll := r.InlineStyle.WebVTTScroll
+ if scroll == "" && r.Style != nil && r.Style.InlineStyle != nil {
+ scroll = r.Style.InlineStyle.WebVTTScroll
+ }
+ if scroll != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("scroll", []byte("scroll="+scroll)),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Viewport anchor
+ va := r.InlineStyle.WebVTTViewportAnchor
+ if va == "" && r.Style != nil && r.Style.InlineStyle != nil {
+ va = r.Style.InlineStyle.WebVTTViewportAnchor
+ }
+ if va != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("viewportanchor", []byte("viewportanchor="+va)),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Width
+ width := r.InlineStyle.WebVTTWidth
+ if width == "" && r.Style != nil && r.Style.InlineStyle != nil {
+ width = r.Style.InlineStyle.WebVTTWidth
+ }
+ if width != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("width", []byte("width="+width)),
+ ); err != nil {
+ return
+ }
+ }
+
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
+ }
}
if len(s.Regions) > 0 {
- c = append(c, bytesLineSeparator...)
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
+ }
}
// Loop through subtitles
for index, item := range s.Items {
// Add comments
if len(item.Comments) > 0 {
- c = append(c, []byte("NOTE ")...)
+ if _, err = c.Write(astikit.WriteWithLabel("note", []byte("NOTE "))); err != nil {
+ return
+ }
for _, comment := range item.Comments {
- c = append(c, []byte(comment)...)
- c = append(c, bytesLineSeparator...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("comment", []byte(comment)),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ ); err != nil {
+ return
+ }
+ }
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
}
- c = append(c, bytesLineSeparator...)
}
// Add time boundaries
- c = append(c, []byte(strconv.Itoa(index+1))...)
- c = append(c, bytesLineSeparator...)
- c = append(c, []byte(formatDurationWebVTT(item.StartAt))...)
- c = append(c, bytesWebVTTTimeBoundariesSeparator...)
- c = append(c, []byte(formatDurationWebVTT(item.EndAt))...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("index", []byte(strconv.Itoa(index+1))),
+ astikit.WriteWithLabel("line separator", bytesLineSeparator),
+ astikit.WriteWithLabel("start at", []byte(formatDurationWebVTT(item.StartAt))),
+ astikit.WriteWithLabel("time boundaries separator", bytesWebVTTTimeBoundariesSeparator),
+ astikit.WriteWithLabel("end at", []byte(formatDurationWebVTT(item.EndAt))),
+ ); err != nil {
+ return
+ }
// Add styles
if item.InlineStyle != nil {
- if item.InlineStyle.WebVTTAlign != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("align:"+item.InlineStyle.WebVTTAlign)...)
- } else if item.Style != nil && item.Style.InlineStyle != nil && item.Style.InlineStyle.WebVTTAlign != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("align:"+item.Style.InlineStyle.WebVTTAlign)...)
- }
- if item.InlineStyle.WebVTTLine != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("line:"+item.InlineStyle.WebVTTLine)...)
- } else if item.Style != nil && item.Style.InlineStyle != nil && item.Style.InlineStyle.WebVTTLine != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("line:"+item.Style.InlineStyle.WebVTTLine)...)
- }
- if item.InlineStyle.WebVTTPosition != nil {
- c = append(c, bytesSpace...)
- c = append(c, []byte("position:"+item.InlineStyle.WebVTTPosition.String())...)
- } else if item.Style != nil && item.Style.InlineStyle != nil && item.Style.InlineStyle.WebVTTPosition != nil {
- c = append(c, bytesSpace...)
- c = append(c, []byte("position:"+item.Style.InlineStyle.WebVTTPosition.String())...)
+ // Align
+ align := item.InlineStyle.WebVTTAlign
+ if align == "" && item.Style != nil && item.Style.InlineStyle != nil {
+ align = item.Style.InlineStyle.WebVTTAlign
+ }
+ if align != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("align", []byte("align:"+align)),
+ ); err != nil {
+ return
+ }
}
+
+ // Line
+ line := item.InlineStyle.WebVTTLine
+ if line == "" && item.Style != nil && item.Style.InlineStyle != nil {
+ line = item.Style.InlineStyle.WebVTTLine
+ }
+ if line != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("line", []byte("line:"+line)),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Position
+ pos := item.InlineStyle.WebVTTPosition
+ if pos == nil && item.Style != nil && item.Style.InlineStyle != nil {
+ pos = item.Style.InlineStyle.WebVTTPosition
+ }
+ if pos != nil {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("position", []byte("position:"+pos.String())),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Region
if item.Region != nil {
- c = append(c, bytesSpace...)
- c = append(c, []byte("region:"+item.Region.ID)...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("region", []byte("region:"+item.Region.ID)),
+ ); err != nil {
+ return
+ }
}
- if item.InlineStyle.WebVTTSize != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("size:"+item.InlineStyle.WebVTTSize)...)
- } else if item.Style != nil && item.Style.InlineStyle != nil && item.Style.InlineStyle.WebVTTSize != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("size:"+item.Style.InlineStyle.WebVTTSize)...)
+
+ // Size
+ size := item.InlineStyle.WebVTTSize
+ if size == "" && item.Style != nil && item.Style.InlineStyle != nil {
+ size = item.Style.InlineStyle.WebVTTSize
}
- if item.InlineStyle.WebVTTVertical != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("vertical:"+item.InlineStyle.WebVTTVertical)...)
- } else if item.Style != nil && item.Style.InlineStyle != nil && item.Style.InlineStyle.WebVTTVertical != "" {
- c = append(c, bytesSpace...)
- c = append(c, []byte("vertical:"+item.Style.InlineStyle.WebVTTVertical)...)
+ if size != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("size", []byte("size:"+size)),
+ ); err != nil {
+ return
+ }
+ }
+
+ // Vertical
+ vertical := item.InlineStyle.WebVTTVertical
+ if vertical == "" && item.Style != nil && item.Style.InlineStyle != nil {
+ vertical = item.Style.InlineStyle.WebVTTVertical
+ }
+ if vertical != "" {
+ if _, err = c.Write(
+ astikit.WriteWithLabel("space", bytesSpace),
+ astikit.WriteWithLabel("vertical", []byte("vertical:"+vertical)),
+ ); err != nil {
+ return
+ }
}
}
- // Add new line
- c = append(c, bytesLineSeparator...)
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
+ }
- // Loop through lines
+ // Add lines
for _, l := range item.Lines {
- c = append(c, l.webVTTBytes()...)
+ if err = l.writeWebVTT(c); err != nil {
+ return
+ }
}
// Add new line
- c = append(c, bytesLineSeparator...)
- }
-
- // Remove last new line
- c = c[:len(c)-1]
-
- // Write
- if _, err = o.Write(c); err != nil {
- err = fmt.Errorf("astisub: writing failed: %w", err)
- return
+ if index < len(s.Items)-1 {
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
+ }
+ }
}
return
}
-func (l Line) webVTTBytes() (c []byte) {
+func (l Line) writeWebVTT(c *astikit.WriteChainer) (err error) {
+ // Voice name
if l.VoiceName != "" {
- c = append(c, []byte("")...)
+ if _, err = c.Write(
+ astikit.WriteWithLabel("voice start", []byte("")),
+ ); err != nil {
+ return
+ }
}
+
+ // Items
for idx := 0; idx < len(l.Items); idx++ {
var previous, next *LineItem
if idx > 0 {
@@ -669,16 +787,23 @@ func (l Line) webVTTBytes() (c []byte) {
if idx < len(l.Items)-1 {
next = &l.Items[idx+1]
}
- c = append(c, l.Items[idx].webVTTBytes(previous, next)...)
+ if err = l.Items[idx].writeWebVTT(c, previous, next); err != nil {
+ return
+ }
+ }
+
+ if _, err = c.Write(astikit.WriteWithLabel("line separator", bytesLineSeparator)); err != nil {
+ return
}
- c = append(c, bytesLineSeparator...)
return
}
-func (li LineItem) webVTTBytes(previous, next *LineItem) (c []byte) {
+func (li LineItem) writeWebVTT(c *astikit.WriteChainer, previous, next *LineItem) (err error) {
// Add timestamp
- if li.StartAt > 0 {
- c = append(c, []byte("<"+formatDurationWebVTT(li.StartAt)+">")...)
+ if _, err = c.Write(
+ astikit.WriteWithCondition("start at", []byte("<"+formatDurationWebVTT(li.StartAt)+">"), li.StartAt > 0),
+ ); err != nil {
+ return
}
// Get color - only add TTMLColor-based tag if there are no WebVTT color tags
@@ -698,30 +823,40 @@ func (li LineItem) webVTTBytes(previous, next *LineItem) (c []byte) {
}
}
- // Append
+ // Write
if color != "" {
- c = append(c, []byte("")...)
+ if _, err = c.Write(astikit.WriteWithLabel("color start", []byte(""))); err != nil {
+ return
+ }
}
if li.InlineStyle != nil {
for idx, tag := range li.InlineStyle.WebVTTTags {
if previous != nil && previous.InlineStyle != nil && len(previous.InlineStyle.WebVTTTags) > idx && tag.Name == previous.InlineStyle.WebVTTTags[idx].Name {
continue
}
- c = append(c, []byte(tag.startTag())...)
+ if _, err = c.Write(astikit.WriteWithLabel("tag start", []byte(tag.startTag()))); err != nil {
+ return
+ }
}
}
- c = append(c, []byte(escapeHTML(li.Text))...)
+ if _, err = c.Write(astikit.WriteWithLabel("text", []byte(escapeHTML(li.Text)))); err != nil {
+ return
+ }
if li.InlineStyle != nil {
for i := len(li.InlineStyle.WebVTTTags) - 1; i >= 0; i-- {
tag := li.InlineStyle.WebVTTTags[i]
if next != nil && next.InlineStyle != nil && len(next.InlineStyle.WebVTTTags) > i && tag.Name == next.InlineStyle.WebVTTTags[i].Name {
continue
}
- c = append(c, []byte(tag.endTag())...)
+ if _, err = c.Write(astikit.WriteWithLabel("tag end", []byte(tag.endTag()))); err != nil {
+ return
+ }
}
}
if color != "" {
- c = append(c, []byte("")...)
+ if _, err = c.Write(astikit.WriteWithLabel("color end", []byte(""))); err != nil {
+ return
+ }
}
return
}
diff --git a/webvtt_internal_test.go b/webvtt_internal_test.go
index f77b718..28de9b0 100644
--- a/webvtt_internal_test.go
+++ b/webvtt_internal_test.go
@@ -1,12 +1,13 @@
package astisub
import (
+ "bytes"
"strconv"
"testing"
"time"
+ "github.com/asticode/go-astikit"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
)
func TestParseTextWebVTT(t *testing.T) {
@@ -165,7 +166,8 @@ func TestCueVoiceSpanRegex(t *testing.T) {
}
func TestLineWebVTTBytes(t *testing.T) {
- require.Equal(t, "1 2 3\n", string(Line{Items: []LineItem{
+ w := &bytes.Buffer{}
+ err := Line{Items: []LineItem{
{
InlineStyle: &StyleAttributes{WebVTTTags: []WebVTTTag{
{Name: "t1"},
@@ -185,5 +187,7 @@ func TestLineWebVTTBytes(t *testing.T) {
}},
Text: " 3",
},
- }}.webVTTBytes()))
+ }}.writeWebVTT(astikit.NewWriteChainer(w))
+ assert.NoError(t, err)
+ assert.Equal(t, "1 2 3\n", w.String())
}
diff --git a/webvtt_test.go b/webvtt_test.go
index 0771cd4..f677363 100644
--- a/webvtt_test.go
+++ b/webvtt_test.go
@@ -347,3 +347,16 @@ Normal text with magenta and unknown color`
assert.Nil(t, unknownColorItem.InlineStyle.TTMLColor) // Unknown color should not be converted
assert.Nil(t, unknownColorItem.InlineStyle.TTMLBackgroundColor)
}
+
+func BenchmarkWriteToWebVTT(b *testing.B) {
+ s, err := astisub.OpenFile("./testdata/example-in.vtt")
+ if err != nil {
+ b.Fatal(err)
+ }
+ w := &bytes.Buffer{}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ w.Reset()
+ s.WriteToWebVTT(w)
+ }
+}