diff --git a/go.mod b/go.mod index d7a20dfe..567e3b3a 100644 --- a/go.mod +++ b/go.mod @@ -41,6 +41,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/multiformats/go-multihash v0.2.3 github.com/orandin/slog-gorm v1.4.0 + github.com/patrickmn/go-cache v2.1.0+incompatible github.com/peterbourgon/ff/v3 v3.4.0 github.com/pion/interceptor v0.1.37 github.com/pion/rtcp v1.2.15 @@ -54,6 +55,7 @@ require ( github.com/streamplace/atproto-oauth-golang v0.0.0-20250619231223-a9c04fb888ac github.com/streamplace/oatproxy v0.0.0-20250722215839-1c878921d185 github.com/stretchr/testify v1.10.0 + github.com/tdewolff/canvas v0.0.0-20250728095813-50d4cb1eee71 github.com/whyrusleeping/cbor-gen v0.3.1 github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6 gitlab.com/gitlab-org/release-cli v0.18.0 @@ -61,7 +63,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 go.opentelemetry.io/otel/sdk v1.36.0 go.opentelemetry.io/otel/trace v1.36.0 - golang.org/x/image v0.22.0 + golang.org/x/image v0.30.0 golang.org/x/net v0.43.0 golang.org/x/sync v0.16.0 golang.org/x/term v0.34.0 @@ -99,6 +101,8 @@ require ( cloud.google.com/go/iam v1.2.0 // indirect cloud.google.com/go/longrunning v0.6.0 // indirect cloud.google.com/go/storage v1.43.0 // indirect + codeberg.org/go-latex/latex v0.1.0 // indirect + codeberg.org/go-pdf/fpdf v0.11.1 // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect @@ -109,9 +113,15 @@ require ( github.com/Antonboom/testifylint v1.6.1 // indirect github.com/AxisCommunications/go-dpop v1.1.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect + github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect + github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect github.com/BurntSushi/toml v1.5.0 // indirect + github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect + github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 // indirect + github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f // indirect github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect + github.com/Kagami/go-avif v0.1.0 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/MicahParks/keyfunc v1.9.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -127,6 +137,7 @@ require ( github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/alingse/nilnesserr v0.2.0 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.2.0 // indirect @@ -134,6 +145,8 @@ require ( github.com/asticode/go-astits v1.13.0 // indirect github.com/aws/aws-sdk-go v1.44.273 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/benoitkugler/textlayout v0.3.1 // indirect + github.com/benoitkugler/textprocessing v0.0.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bits-and-blooms/bitset v1.24.0 // indirect github.com/bkielbasa/cyclop v1.2.3 // indirect @@ -196,6 +209,7 @@ require ( github.com/ghostiam/protogetter v0.3.15 // indirect github.com/go-chi/chi/v5 v5.1.0 // indirect github.com/go-critic/go-critic v0.13.0 // indirect + github.com/go-fonts/latin-modern v0.3.3 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-kit/log v0.2.1 // indirect @@ -206,6 +220,7 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-text/typesetting v0.3.0 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect github.com/go-toolsmith/astcopy v1.1.0 // indirect github.com/go-toolsmith/astequal v1.2.0 // indirect @@ -299,7 +314,8 @@ require ( github.com/kisielk/errcheck v1.9.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect github.com/klauspost/compress v1.18.0 // indirect - github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect + github.com/kolesa-team/go-webp v1.0.5 // indirect github.com/kulti/thelper v0.6.3 // indirect github.com/kunwardeep/paralleltest v1.0.14 // indirect github.com/labstack/gommon v0.4.2 // indirect @@ -363,7 +379,6 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect @@ -428,12 +443,17 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/spf13/viper v1.12.0 // indirect + github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect + github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.1 // indirect github.com/supranational/blst v0.3.15 // indirect github.com/tdakkota/asciicheck v0.4.1 // indirect + github.com/tdewolff/font v0.0.0-20250430140153-b654fd8acba3 // indirect + github.com/tdewolff/minify/v2 v2.23.4 // indirect + github.com/tdewolff/parse/v2 v2.8.0 // indirect github.com/tetafro/godot v1.5.1 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect @@ -451,6 +471,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect github.com/vektah/gqlparser/v2 v2.5.22 // indirect github.com/vincent-petithory/dataurl v1.0.0 // indirect + github.com/wcharczuk/go-chart/v2 v2.1.2 // indirect github.com/wlynxg/anet v0.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect @@ -480,11 +501,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.41.0 // indirect - golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect + golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 // indirect golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect golang.org/x/mod v0.27.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/text v0.28.0 // indirect + gonum.org/v1/plot v0.16.0 // indirect google.golang.org/appengine/v2 v2.0.2 // indirect google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect @@ -501,6 +523,9 @@ require ( honnef.co/go/tools v0.6.1 // indirect howett.net/plist v1.0.0 // indirect lukechampine.com/blake3 v1.4.1 // indirect + modernc.org/knuth v0.5.5 // indirect + modernc.org/token v1.1.0 // indirect mvdan.cc/gofumpt v0.8.0 // indirect mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect + star-tex.org/x/tex v0.7.1 // indirect ) diff --git a/go.sum b/go.sum index 9845cb00..94ab06f8 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,14 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= +codeberg.org/go-fonts/dejavu v0.4.0 h1:2yn58Vkh4CFK3ipacWUAIE3XVBGNa0y1bc95Bmfx91I= +codeberg.org/go-fonts/dejavu v0.4.0/go.mod h1:abni088lmhQJvso2Lsb7azCKzwkfcnttl6tL1UTWKzg= +codeberg.org/go-fonts/liberation v0.5.0 h1:SsKoMO1v1OZmzkG2DY+7ZkCL9U+rrWI09niOLfQ5Bo0= +codeberg.org/go-fonts/liberation v0.5.0/go.mod h1:zS/2e1354/mJ4pGzIIaEtm/59VFCFnYC7YV6YdGl5GU= +codeberg.org/go-latex/latex v0.1.0 h1:hoGO86rIbWVyjtlDLzCqZPjNykpWQ9YuTZqAzPcfL3c= +codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9Dny04MHMw= +codeberg.org/go-pdf/fpdf v0.11.1 h1:U8+coOTDVLxHIXZgGvkfQEi/q0hYHYvEHFuGNX2GzGs= +codeberg.org/go-pdf/fpdf v0.11.1/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= @@ -59,6 +67,10 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= firebase.google.com/go/v4 v4.14.1 h1:4qiUETaFRWoFGE1XP5VbcEdtPX93Qs+8B/7KvP2825g= firebase.google.com/go/v4 v4.14.1/go.mod h1:fgk2XshgNDEKaioKco+AouiegSI9oTWVqRaBdTTGBoM= +git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= +git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= +git.sr.ht/~sbinet/gg v0.6.0 h1:RIzgkizAk+9r7uPzf/VfbJHBMKUr0F5hRFxTUGMnt38= +git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= git.stream.place/streamplace/c2pa-go v0.7.0 h1:cRbOxgAFgM42XDmvK39ImYP/LrJEekYZ+GoxMGIcakk= git.stream.place/streamplace/c2pa-go v0.7.0/go.mod h1:ymtm/Gk3K8Q67SuBoZUqmA0prdymNwAI9BjLj6plhBM= github.com/4meepo/tagalign v1.4.2 h1:0hcLHPGMjDyM1gHG58cS73aQF8J4TdVR96TZViorO9E= @@ -75,16 +87,28 @@ github.com/Antonboom/testifylint v1.6.1 h1:6ZSytkFWatT8mwZlmRCHkWz1gPi+q6UBSbiej github.com/Antonboom/testifylint v1.6.1/go.mod h1:k+nEkathI2NFjKO6HvwmSrbzUcQ6FAnbZV+ZRrnXPLI= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA= +github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ= +github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= +github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc h1:7D+Bh06CRPCJO3gr2F7h1sriovOZ8BMhca2Rg85c2nk= +github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 h1:O/r2Sj+8QcMF7V5IcmiE2sMFV2q3J47BEirxbXJAdzA= +github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k= +github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f h1:l7moT9o/v/9acCWA64Yz/HDLqjcRTvc0noQACi4MsJw= +github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f/go.mod h1:vIOkSdX3NDCPwgu8FIuTat2zDF0FPXXQ0RYFRy+oQic= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 h1:Sz1JIXEcSfhz7fUi7xHnhpIE0thVASYjvosApmHuD2k= github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1/go.mod h1:n/LSCXNuIYqVfBlVXyHfMQkZDdp1/mmxfSjADd3z1Zg= +github.com/Kagami/go-avif v0.1.0 h1:8GHAGLxCdFfhpd4Zg8j1EqO7rtcQNenxIDerC/uu68w= +github.com/Kagami/go-avif v0.1.0/go.mod h1:OPmPqzNdQq3+sXm0HqaUJQ9W/4k+Elbc3RSfJUemDKA= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/MicahParks/keyfunc v1.9.0 h1:lhKd5xrFHLNOWrDc4Tyb/Q1AJ4LCzQ48GVJyVIID3+o= @@ -109,6 +133,8 @@ github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpH github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY= github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.17.2 h1:Rm81SCZ2mPoH+Q8ZCc/9YvzPUN/E7HgPiPJD8SLV6GI= @@ -135,6 +161,8 @@ github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEW github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= @@ -159,6 +187,13 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE= +github.com/benoitkugler/textlayout v0.3.0/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w= +github.com/benoitkugler/textlayout v0.3.1 h1:hXCAJv3/8oF2mm68jledvbq85l6dA+aOYkwnzH5v4F8= +github.com/benoitkugler/textlayout v0.3.1/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w= +github.com/benoitkugler/textlayout-testdata v0.1.1/go.mod h1:i/qZl09BbUOtd7Bu/W1CAubRwTWrEXWq6JwMkw8wYxo= +github.com/benoitkugler/textprocessing v0.0.3 h1:Q2X+Z6vxuW5Bxn1R9RaNt0qcprBfpc2hEUDeTlz90Ng= +github.com/benoitkugler/textprocessing v0.0.3/go.mod h1:/4bLyCf1QYywunMK3Gf89Nhb50YI/9POewqrLxWhxd4= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -191,6 +226,8 @@ github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQU github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= +github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc= github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8= github.com/catenacyber/perfsprint v0.9.1 h1:5LlTp4RwTooQjJCvGEFV6XksZvWE7wCOUvjD2z0vls0= @@ -373,6 +410,8 @@ github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw= github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-critic/go-critic v0.13.0 h1:kJzM7wzltQasSUXtYyTl6UaPVySO6GkaR1thFnJ6afY= github.com/go-critic/go-critic v0.13.0/go.mod h1:M/YeuJ3vOCQDnP2SU+ZhjgRzwzcBW87JqLpMJLrZDLI= +github.com/go-fonts/latin-modern v0.3.3 h1:g2xNgI8yzdNzIVm+qvbMryB6yGPe0pSMss8QT3QwlJ0= +github.com/go-fonts/latin-modern v0.3.3/go.mod h1:tHaiWDGze4EPB0Go4cLT5M3QzRY3peya09Z/8KSCrpY= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= @@ -425,6 +464,10 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4= +github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY= +github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0= +github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= @@ -540,6 +583,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -791,8 +835,10 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= -github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kolesa-team/go-webp v1.0.5 h1:GZQHJBaE8dsNKZltfwqsL0qVJ7vqHXsfA+4AHrQW3pE= +github.com/kolesa-team/go-webp v1.0.5/go.mod h1:QmJu0YHXT3ex+4SgUvs+a+1SFCDcCqyZg+LbIuNNTnE= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= @@ -1217,6 +1263,14 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= +github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE= +github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q= +github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ= +github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE= +github.com/srwiley/scanFT v0.0.0-20220128184157-0d1ee492111f h1:uLR2GaV0kWYZ3Ns3l3sjtiN+mOWAQadvrL8HXcyKjl0= +github.com/srwiley/scanFT v0.0.0-20220128184157-0d1ee492111f/go.mod h1:LZwgIPG9X6nH6j5Ef+xMFspl6Hru4b5EJxzMfeqHYJY= +github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388 h1:ZdkidVdpLW13BQ9a+/3uerT2ezy9J7KQWH18JCfhDmI= +github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388/go.mod h1:C/WY5lmWfMtPFYYBTd3Lzdn4FTLr+RxlIeiBNye+/os= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4= @@ -1254,6 +1308,16 @@ github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tdakkota/asciicheck v0.4.1 h1:bm0tbcmi0jezRA2b5kg4ozmMuGAFotKI3RZfrhfovg8= github.com/tdakkota/asciicheck v0.4.1/go.mod h1:0k7M3rCfRXb0Z6bwgvkEIMleKH3kXNz9UqJ9Xuqopr8= +github.com/tdewolff/canvas v0.0.0-20250728095813-50d4cb1eee71 h1:CIWvhVDNsEQd9T3zk74EjZ3isXamdGFxxSO4U1vjtSs= +github.com/tdewolff/canvas v0.0.0-20250728095813-50d4cb1eee71/go.mod h1:r5O5UHm7WMj6o9mbY1gdBHkg308r0EcfS/10YBbBLHI= +github.com/tdewolff/font v0.0.0-20250430140153-b654fd8acba3 h1:DztDdVAimSmI3eDKlMP1XSpeEYyhLRt9tPPivB7SNz8= +github.com/tdewolff/font v0.0.0-20250430140153-b654fd8acba3/go.mod h1:eDnkgh2pt95UFXk0GsUv2JNj5gumg78c02QX0TdcwTA= +github.com/tdewolff/minify/v2 v2.23.4 h1:qyHu5oFeElhUDsmtXKQKoNUKA1r8126eWslvPYoX/Vw= +github.com/tdewolff/minify/v2 v2.23.4/go.mod h1:2RI9tiIrzJU1Z5EasXEPaI1MqobRyxKHOOgrRkq5oEw= +github.com/tdewolff/parse/v2 v2.8.0 h1:jW0afj6zpUGXuZTwJ7/UfP2SddyLalb/SDryjaMTkA4= +github.com/tdewolff/parse/v2 v2.8.0/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo= +github.com/tdewolff/test v1.0.11 h1:FdLbwQVHxqG16SlkGveC0JVyrJN62COWTRyUFzfbtBE= +github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= @@ -1299,6 +1363,8 @@ github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsX github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= +github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E= +github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= github.com/whyrusleeping/cbor-gen v0.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0= @@ -1323,6 +1389,8 @@ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavM github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= @@ -1417,6 +1485,8 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +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.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1429,16 +1499,18 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 h1:R9PFI6EUdfVKgwKjZef7QIwGcBKu86OEFpJ9nUEP2l4= -golang.org/x/exp v0.0.0-20250718183923-645b1fa84792/go.mod h1:A+z0yzpGtvnG90cToK5n2tu8UJVP2XUATh+r+sfOOOc= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE= +golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rPv1pNOQtl1I8knsO4S9trOxNMOLVP4= golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.22.0 h1:UtK5yLUzilVrkjMAZAZ34DXGpASN8i8pj8g+O+yd10g= -golang.org/x/image v0.22.0/go.mod h1:9hPFhljd4zZ1GNSIZJ49sqbp45GKK9t6w+iXvGqZUz4= +golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= +golang.org/x/image v0.30.0 h1:jD5RhkmVAnjqaCUXfbGBrn3lpxbknfN9w2UhHHU+5B4= +golang.org/x/image v0.30.0/go.mod h1:SAEUTxCCMWSrJcCy/4HwavEsfZZJlYxeHLc6tTiAe/c= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1466,6 +1538,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +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.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1500,6 +1574,7 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1516,6 +1591,8 @@ 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.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +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.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1543,6 +1620,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ 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.4.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.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1603,8 +1682,11 @@ golang.org/x/sys v0.6.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.13.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.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= 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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1614,6 +1696,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= 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.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +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.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1629,6 +1713,9 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 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.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1697,10 +1784,11 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= -golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY= -golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1709,6 +1797,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gonum.org/v1/plot v0.16.0 h1:dK28Qx/Ky4VmPUN/2zeW0ELyM6ucDnBAj5yun7M9n1g= +gonum.org/v1/plot v0.16.0/go.mod h1:Xz6U1yDMi6Ni6aaXILqmVIb6Vro8E+K7Q/GeeH+Pn0c= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1857,6 +1947,10 @@ howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= +modernc.org/knuth v0.5.5 h1:6lap2U/ISm8aC/4NU58ALFCRllNPaK0EZcIGY/oDgUg= +modernc.org/knuth v0.5.5/go.mod h1:e5SBb35HQBj2aFwbBO3ClPcViLY3Wi0LzaOd7c/3qMk= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k= mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg= mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8= @@ -1864,7 +1958,11 @@ mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5gin pgregory.net/rapid v1.1.0 h1:CMa0sjHSru3puNx+J0MIAuiiEV4N0qj8/cMWGBBCsjw= pgregory.net/rapid v1.1.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +star-tex.org/x/tex v0.7.1 h1:4qGAByRyY0WQsOjtcHlxz+FgrYxz8fzxIds2Gjepp5U= +star-tex.org/x/tex v0.7.1/go.mod h1:Y3y0U7sZTltTh/CDZIx0oAtMjG7eMaTuTtvDZGdyhJo= diff --git a/js/app/app.go b/js/app/app.go index 887f3739..0ef12106 100644 --- a/js/app/app.go +++ b/js/app/app.go @@ -9,6 +9,9 @@ import ( //go:embed all:dist/** var AllFiles embed.FS +//go:embed all:assets/** +var AssetFiles embed.FS + //go:embed package.json var pkg []byte @@ -21,6 +24,15 @@ func Files() (fs.FS, error) { return rootFiles, nil } +// fetch assets including fonts +func Assets() (fs.FS, error) { + assetFiles, err := fs.Sub(AssetFiles, "assets") + if err != nil { + return nil, err + } + return assetFiles, nil +} + func PackageJSON() (map[string]any, error) { var data map[string]any err := json.Unmarshal(pkg, &data) diff --git a/js/app/assets/fonts/AtkinsonHyperlegibleNext-Bold.ttf b/js/app/assets/fonts/AtkinsonHyperlegibleNext-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a23aed3e7757d60dd2c3bc610a807a396a0b13c3 GIT binary patch literal 47968 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ృPbAv*CM%T9qg$er_AZeRf4qPWN6bl*)3xkq2 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 Fqyb3K)-3=4 literal 0 HcmV?d00001 diff --git a/js/docs/src/content/docs/lex-reference/live/place-stream-live-getprofilecard.md b/js/docs/src/content/docs/lex-reference/live/place-stream-live-getprofilecard.md new file mode 100644 index 00000000..0bae221a --- /dev/null +++ b/js/docs/src/content/docs/lex-reference/live/place-stream-live-getprofilecard.md @@ -0,0 +1,66 @@ +--- +title: place.stream.live.getProfileCard +description: Reference for the place.stream.live.getProfileCard lexicon +--- + +**Lexicon Version:** 1 + +## Definitions + + + +### `main` + +**Type:** `query` + +Get an OG image associated with a given account. + +**Parameters:** + +| Name | Type | Req'd | Description | Constraints | +| ---- | -------- | ----- | --------------------------------- | ----------- | +| `id` | `string` | ✅ | The DID or handle of the account. | | + +**Output:** + +- **Encoding:** `*/*` +- **Schema:** + +_Schema not defined._ **Possible Errors:** + +- `RepoNotFound` + +--- + +## Lexicon Source + +```json +{ + "lexicon": 1, + "id": "place.stream.live.getProfileCard", + "defs": { + "main": { + "type": "query", + "description": "Get an OG image associated with a given account.", + "parameters": { + "type": "params", + "required": ["id"], + "properties": { + "id": { + "type": "string", + "description": "The DID or handle of the account." + } + } + }, + "output": { + "encoding": "*/*" + }, + "errors": [ + { + "name": "RepoNotFound" + } + ] + } + } +} +``` diff --git a/js/docs/src/content/docs/lex-reference/openapi.json b/js/docs/src/content/docs/lex-reference/openapi.json index 73b72dd1..84f908a7 100644 --- a/js/docs/src/content/docs/lex-reference/openapi.json +++ b/js/docs/src/content/docs/lex-reference/openapi.json @@ -55,6 +55,59 @@ ] } }, + "/xrpc/place.stream.live.getProfileCard": { + "get": { + "summary": "Get an OG image associated with a given account.", + "operationId": "place.stream.live.getProfileCard", + "tags": ["place.stream.live"], + "responses": { + "200": { + "description": "Success", + "content": { + "*/*": { + "schema": {} + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "RepoNotFound" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "description": "The DID or handle of the account.", + "schema": { + "type": "string", + "description": "The DID or handle of the account." + } + } + ] + } + }, "/xrpc/place.stream.live.getSegments": { "get": { "summary": "Get a list of livestream segments for a user", diff --git a/lexicons/place/stream/live/getProfileCard.json b/lexicons/place/stream/live/getProfileCard.json new file mode 100644 index 00000000..00d990f8 --- /dev/null +++ b/lexicons/place/stream/live/getProfileCard.json @@ -0,0 +1,24 @@ +{ + "lexicon": 1, + "id": "place.stream.live.getProfileCard", + "defs": { + "main": { + "type": "query", + "description": "Get an OG image associated with a given account.", + "parameters": { + "type": "params", + "required": ["id"], + "properties": { + "id": { + "type": "string", + "description": "The DID or handle of the account." + } + } + }, + "output": { + "encoding": "*/*" + }, + "errors": [{ "name": "RepoNotFound" }] + } + } +} diff --git a/pkg/api/api.go b/pkg/api/api.go index acb9432b..cf9db731 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -135,7 +135,7 @@ func (a *StreamplaceAPI) Handler(ctx context.Context) (http.Handler, error) { Recorder: metrics.NewRecorder(metrics.Config{}), }) var xrpc http.Handler - xrpc, err := spxrpc.NewServer(ctx, a.CLI, a.Model, a.op, mdlw) + xrpc, err := spxrpc.NewServer(ctx, a.CLI, a.Model, a.op, mdlw, a.ATSync) if err != nil { return nil, err } diff --git a/pkg/linking/linking.go b/pkg/linking/linking.go index db5cb778..d80ebb53 100644 --- a/pkg/linking/linking.go +++ b/pkg/linking/linking.go @@ -54,7 +54,8 @@ func (l *Linker) GenerateStreamerCard(ctx context.Context, u *url.URL, lsv *stre pageTitle := fmt.Sprintf("@%s | %s", lsv.Author.Handle, u.Host) thumbURL, _ := url.Parse(u.String()) - thumbURL.Path = fmt.Sprintf("/api/playback/%s/stream.jpg", lsv.Author.Did) + thumbURL.Path = "/xrpc/place.stream.live.getProfileCard" + thumbURL.RawQuery = fmt.Sprintf("id=%s", lsv.Author.Did) // Define all meta tags metaTags := []MetaTag{ diff --git a/pkg/spxrpc/og.go b/pkg/spxrpc/og.go new file mode 100644 index 00000000..dfbabfd7 --- /dev/null +++ b/pkg/spxrpc/og.go @@ -0,0 +1,480 @@ +package spxrpc + +import ( + "bytes" + "context" + _ "embed" + "errors" + "fmt" + "image" + "image/color" + _ "image/jpeg" + _ "image/png" + "io" + "math" + "net/http" + "strings" + + imagedraw "image/draw" + + "golang.org/x/image/draw" + "golang.org/x/net/context/ctxhttp" + + "github.com/bluesky-social/indigo/api/bsky" + "github.com/bluesky-social/indigo/xrpc" + "github.com/labstack/echo/v4" + "github.com/patrickmn/go-cache" + "github.com/tdewolff/canvas" + "github.com/tdewolff/canvas/renderers" + "stream.place/streamplace/js/app" + "stream.place/streamplace/pkg/aqhttp" + "stream.place/streamplace/pkg/log" +) + +const ( + // Canvas dimensions + ogWidth = 400.0 + ogHeight = 200.0 + + // Card dimensions and positioning + cardPadding = 10.0 + cardWidth = 380.0 + cardHeight = 180.0 + cardRadius = 12.0 + + // Image dimensions and positioning + imageX = 25.0 + imageY = 55.0 + imageWidth = 400 + imageHeight = 480 + imageRadius = 180.0 + imageDPMM = 3.9 + + // Text positioning + textStartX = 135.0 + joinY = 142.0 + subtitleY = 115.0 + descY = 90.0 + + // Font sizes + joinFontSize = 56.0 + minJoinFontSize = 40.0 + subtitleFontSize = 48.0 + descFontSize = 28.0 + placeholderFontSize = 18.0 + + // Available text width + textAvailableWidth = 255.0 + + // Canvas DPI + canvasDPMM = 2.0 +) + +var ( + // Colors + bgColor = color.RGBA{R: 0, G: 0, B: 0, A: 255} + cardColor = color.RGBA{R: 38, G: 38, B: 38, A: 255} + cardBorderColor = color.RGBA{R: 64, G: 64, B: 64, A: 255} + placeholderColor = color.RGBA{R: 240, G: 240, B: 240, A: 255} + placeholderTextColor = color.RGBA{R: 100, G: 100, B: 100, A: 255} + joinTextColor = color.RGBA{R: 255, G: 200, B: 50, A: 255} + subtitleColor = color.RGBA{R: 200, G: 200, B: 200, A: 255} + descColor = color.RGBA{R: 180, G: 180, B: 180, A: 255} + imageBorderColor = color.RGBA{R: 200, G: 200, B: 200, A: 255} +) + +const ( + // Description settings + maxDescriptionLength = 120 + descriptionTruncate = 117 +) + +var ErrUserNotFound = errors.New("user not found") + +// createResponsiveJoinText creates a text box for "Join [username]" that fits within the available width +// by reducing font size and truncating with ellipsis if necessary +func createResponsiveJoinText(fontFamily *canvas.FontFamily, text string, availableWidth float64) (*canvas.Text, float64) { + fontSize := joinFontSize + minFontSize := minJoinFontSize + + for fontSize >= minFontSize { + // Try bold first, fall back to regular if bold fails + face := fontFamily.Face(fontSize, joinTextColor, canvas.FontBold, canvas.FontNormal) + if face == nil { + face = fontFamily.Face(fontSize, joinTextColor, canvas.FontRegular, canvas.FontNormal) + } + + if face != nil { + textBox := canvas.NewTextBox(face, text, availableWidth, 40, canvas.Left, canvas.Center, &canvas.TextOptions{}) + + // Check if text fits + if textBox.Bounds().W() <= availableWidth { + return textBox, fontSize + } + } + + fontSize -= 2.0 // Reduce font size by 2px each iteration + } + + // If we get here, even minimum size doesn't fit, so we need to truncate + face := fontFamily.Face(minFontSize, joinTextColor, canvas.FontBold, canvas.FontNormal) + if face == nil { + face = fontFamily.Face(minFontSize, joinTextColor, canvas.FontRegular, canvas.FontNormal) + } + + // Try progressively shorter versions with ellipsis + for i := len(text) - 1; i > 0; i-- { + truncatedText := text[:i] + "..." + textBox := canvas.NewTextBox(face, truncatedText, availableWidth, 40, canvas.Left, canvas.Center, &canvas.TextOptions{}) + if textBox.Bounds().W() <= availableWidth { + return textBox, minFontSize + } + } + + // Fallback - just ellipsis + return canvas.NewTextBox(face, "...", availableWidth, 40, canvas.Left, canvas.Center, &canvas.TextOptions{}), minFontSize +} + +func (s *Server) handlePlaceStreamLiveGetProfileCard(ctx context.Context, id string) (io.Reader, error) { + if id == "" { + return nil, errors.New("id required") + } + + // Get Echo context to set response headers + c, ok := ctx.Value(echoContextKey).(echo.Context) + if ok { + // Set appropriate headers for image response + c.Response().Header().Set("Content-Type", "image/jpeg") + c.Response().Header().Set("Cache-Control", "public, max-age=300") // 5 minutes + c.Response().Header().Set("X-Content-Type-Options", "nosniff") + } + + // trim ending slash if any + username := strings.TrimRight(id, "/") + + cacheKey := fmt.Sprintf("og_image_%s", username) + if cached, found := s.OGImageCache.Get(cacheKey); found { + imgData := cached.([]byte) + log.Debug(ctx, "OG image cache hit", "username", username, "size_bytes", len(imgData)) + return bytes.NewReader(imgData), nil + } + + imgData, err := s.generateOGImage(ctx, username) + if err != nil { + log.Error(ctx, "failed to generate OG image", "username", username, "error", err) + return nil, err + } + + s.OGImageCache.Set(cacheKey, imgData, cache.DefaultExpiration) + log.Debug(ctx, "OG image generated and cached", "username", username, "size_bytes", len(imgData)) + + return bytes.NewReader(imgData), nil +} + +func downloadImage(ctx context.Context, url string) ([]byte, error) { + if url == "" { + return nil, errors.New("empty URL provided") + } + + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + resp, err := ctxhttp.Do(ctx, &aqhttp.Client, req) + if err != nil { + return nil, fmt.Errorf("HTTP request failed: %w", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("HTTP request failed with status %d: %s", resp.StatusCode, resp.Status) + } + + imageData, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read image data: %w", err) + } + + return imageData, nil +} + +func (s *Server) generateOGImage(ctx context.Context, username string) ([]byte, error) { + // Fetch user profile and avatar from Bluesky + var imageURL string + var handle, description string + + // Set default fallbacks + handle = username + description = "Live streaming platform for creators and their communities." + + profileData, err := s.fetchUserProfile(ctx, username) + if err != nil { + return nil, fmt.Errorf("failed to fetch profile, because %w", err) + } else if profileData != nil { + // Safely extract profile data with nil checks + if profileData.Avatar != nil && *profileData.Avatar != "" { + imageURL = *profileData.Avatar + } + + if profileData.Handle != "" { + handle = profileData.Handle + } + + if profileData.Description != nil && *profileData.Description != "" { + // Truncate description if too long for the image + desc := *profileData.Description + if len(desc) > maxDescriptionLength { + desc = desc[:descriptionTruncate] + "..." + } + description = desc + } + } else { + log.Warn(ctx, "received nil profile data, using fallbacks", "username", username) + } + + // Create new canvas of dimension ogWidth x ogHeight mm for profile card + c := canvas.New(ogWidth, ogHeight) + + // Create a canvas context used to keep drawing state + canvasCtx := canvas.NewContext(c) + + fontAHN := canvas.NewFontFamily("Atkinson Hyperlegible Next") + + regularData, regularDataErr := getAtkinsonRegular() + if regularDataErr != nil { + log.Warn(ctx, "failed to load regular Atkinson font data", "error", regularDataErr) + } + + boldData, boldDataErr := getAtkinsonBold() + if boldDataErr != nil { + log.Warn(ctx, "failed to load bold Atkinson font data", "error", boldDataErr) + } + + var regularErr, boldErr error + if regularDataErr == nil { + regularErr = fontAHN.LoadFont(regularData, 0, canvas.FontRegular) + } + if boldDataErr == nil { + boldErr = fontAHN.LoadFont(boldData, 0, canvas.FontBold) + } + + // If font loading fails, the canvas library will fall back to default fonts + if regularErr != nil { + log.Warn(ctx, "failed to load regular Atkinson font, using fallback", "error", regularErr) + } + if boldErr != nil { + log.Warn(ctx, "failed to load bold Atkinson font, using fallback", "error", boldErr) + } + + // If both custom fonts failed to load, ensure we have a working font family + if (regularDataErr != nil || regularErr != nil) && (boldDataErr != nil || boldErr != nil) { + log.Warn(ctx, "all custom fonts failed to load, using system default") + fontAHN = canvas.NewFontFamily("sans-serif") + } + + // Set black background + canvasCtx.SetFillColor(bgColor) + canvasCtx.DrawPath(0, 0, canvas.Rectangle(ogWidth, ogHeight)) + canvasCtx.Fill() + + // Create neutral-800 rounded card + canvasCtx.SetFillColor(cardColor) + canvasCtx.DrawPath(cardPadding, cardPadding, canvas.RoundedRectangle(cardWidth, cardHeight, cardRadius)) + canvasCtx.Fill() + + // Add subtle border to card + canvasCtx.SetStrokeColor(cardBorderColor) + canvasCtx.SetStrokeWidth(1) + canvasCtx.DrawPath(cardPadding, cardPadding, canvas.RoundedRectangle(cardWidth, cardHeight, cardRadius)) + canvasCtx.Stroke() + + // Try to download and decode the image in memory + var img image.Image + if imageURL != "" { + imageData, downloadErr := downloadImage(ctx, imageURL) + if downloadErr != nil { + log.Warn(ctx, "failed to download profile image", "username", username, "image_url", imageURL, "error", downloadErr) + } else { + // Decode image directly from memory + reader := bytes.NewReader(imageData) + var err error + img, _, err = image.Decode(reader) + if err != nil { + log.Warn(ctx, "failed to decode image", "username", username, "error", err) + img = nil + } + } + } + + if img == nil { + // Fallback to placeholder if download or loading fails - positioned within card + canvasCtx.SetFillColor(placeholderColor) + canvasCtx.DrawPath(imageX, 50, canvas.RoundedRectangle(100, 120, 8)) + canvasCtx.Fill() + + imageFace := fontAHN.Face(placeholderFontSize, placeholderTextColor, canvas.FontBold, canvas.FontNormal) + imageText := canvas.NewTextBox(imageFace, "Streamplace", 100, 30, canvas.Center, canvas.Center, &canvas.TextOptions{}) + canvasCtx.DrawText(imageX, 100, imageText) + } else { + // High-quality avatar processing with circular masking + avatarDisplaySize := imageRadius * 2 / imageDPMM + avatarSize := int(avatarDisplaySize * canvasDPMM) + + // High-quality scaling with center cropping + bounds := img.Bounds() + srcWidth, srcHeight := bounds.Dx(), bounds.Dy() + + // Calculate square crop (center crop for circular fit) + cropSize := srcWidth + if srcHeight < cropSize { + cropSize = srcHeight + } + cropOffsetX := (srcWidth - cropSize) / 2 + cropOffsetY := (srcHeight - cropSize) / 2 + cropRect := image.Rect( + bounds.Min.X+cropOffsetX, + bounds.Min.Y+cropOffsetY, + bounds.Min.X+cropOffsetX+cropSize, + bounds.Min.Y+cropOffsetY+cropSize, + ) + + scaledAvatar := image.NewRGBA(image.Rect(0, 0, avatarSize, avatarSize)) + draw.CatmullRom.Scale(scaledAvatar, scaledAvatar.Bounds(), img, cropRect, draw.Over, nil) + + // Create circular alpha mask + mask := image.NewAlpha(image.Rect(0, 0, avatarSize, avatarSize)) + center := avatarSize / 2 + radius := float64(center) + + // Generate anti-aliased circular mask + for y := 0; y < avatarSize; y++ { + for x := 0; x < avatarSize; x++ { + dx := float64(x - center) + dy := float64(y - center) + distance := math.Sqrt(dx*dx + dy*dy) + + if distance <= radius { + alpha := 255.0 + if distance > radius-1 { + alpha = 255.0 * (radius - distance) + } + mask.SetAlpha(x, y, color.Alpha{uint8(alpha)}) + } + } + } + + // Apply circular mask + maskedAvatar := image.NewRGBA(image.Rect(0, 0, avatarSize, avatarSize)) + imagedraw.DrawMask(maskedAvatar, maskedAvatar.Bounds(), scaledAvatar, image.Point{}, mask, image.Point{}, imagedraw.Over) + + // Add circular border + avatarCenterX := imageX + avatarDisplaySize/2 + avatarCenterY := imageY + avatarDisplaySize/2 + canvasCtx.SetStrokeColor(imageBorderColor) + canvasCtx.SetStrokeWidth(3) + canvasCtx.DrawPath(avatarCenterX, avatarCenterY, canvas.Circle(avatarDisplaySize/2)) + canvasCtx.Stroke() + + // Draw the final circular avatar + canvasCtx.DrawImage(imageX, imageY, maskedAvatar, canvas.DPMM(canvasDPMM)) + } + + // Create unified responsive "Join @handle" text + joinUserContent := fmt.Sprintf("Join @%s", handle) + + availableWidth := textAvailableWidth // Full available width for the text + joinText, _ := createResponsiveJoinText(fontAHN, joinUserContent, availableWidth) + canvasCtx.DrawText(textStartX, joinY, joinText) + + // Add "streaming on Stream.place" subtitle + onFace := fontAHN.Face(subtitleFontSize, subtitleColor, canvas.FontRegular, canvas.FontNormal) + onText := canvas.NewTextBox(onFace, "streaming on Stream.place", 250, 30, canvas.Left, canvas.Center, &canvas.TextOptions{}) + canvasCtx.DrawText(textStartX, subtitleY, onText) + + // Add user description or promotional text + descFace := fontAHN.Face(descFontSize, descColor, canvas.FontRegular, canvas.FontNormal) + descText := canvas.NewTextBox(descFace, description, 230, 30, canvas.Left, canvas.Center, &canvas.TextOptions{}) + canvasCtx.DrawText(textStartX, descY, descText) + + b := &bytes.Buffer{} + if err := c.Write(b, renderers.JPEG(canvas.DPMM(canvasDPMM))); err != nil { + return nil, fmt.Errorf("failed to render canvas to buffer: %w", err) + } + + return b.Bytes(), nil +} + +// getAtkinsonRegular returns the regular Atkinson Hyperlegible Next font data from app filesystem +func getAtkinsonRegular() ([]byte, error) { + files, err := app.Assets() + if err != nil { + return nil, fmt.Errorf("failed to get app assets: %w", err) + } + + file, err := files.Open("fonts/AtkinsonHyperlegibleNext-Regular.ttf") + if err != nil { + return nil, fmt.Errorf("failed to open regular font: %w", err) + } + defer file.Close() + + data, err := io.ReadAll(file) + if err != nil { + return nil, fmt.Errorf("failed to read regular font: %w", err) + } + + return data, nil +} + +// getAtkinsonBold returns the bold Atkinson Hyperlegible Next font data from app filesystem +func getAtkinsonBold() ([]byte, error) { + files, err := app.Assets() + if err != nil { + return nil, fmt.Errorf("failed to get app assets: %w", err) + } + + file, err := files.Open("fonts/AtkinsonHyperlegibleNext-Bold.ttf") + if err != nil { + return nil, fmt.Errorf("failed to open bold font: %w", err) + } + defer file.Close() + + data, err := io.ReadAll(file) + if err != nil { + return nil, fmt.Errorf("failed to read bold font: %w", err) + } + + return data, nil +} + +func (s *Server) fetchUserProfile(ctx context.Context, username string) (*bsky.ActorDefs_ProfileViewDetailed, error) { + // Use ATSync to resolve username to DID, then fetch full profile from Bluesky + var actor string + + // First try to resolve via internal DB + repo, err := s.ATSync.Model.GetRepoByHandleOrDID(username) + if err != nil { + return nil, fmt.Errorf("%w: %w", ErrUserNotFound, err) + } else if repo != nil { + // Use the DID as it's the most reliable identifier + actor = repo.DID + } else { + return nil, fmt.Errorf("no repo found for username: %s (%w)", username, ErrUserNotFound) + } + + // Fetch full profile from Bluesky public API + client := &xrpc.Client{ + Host: "https://public.api.bsky.app", + } + + profile, err := bsky.ActorGetProfile(ctx, client, actor) + if err != nil { + return nil, fmt.Errorf("failed to fetch profile from Bluesky for '%s': %w", actor, err) + } + + if profile == nil { + return nil, fmt.Errorf("received nil profile from Bluesky API for '%s'", actor) + } + + return profile, nil +} diff --git a/pkg/spxrpc/spxrpc.go b/pkg/spxrpc/spxrpc.go index 34f8bf8e..83b1b993 100644 --- a/pkg/spxrpc/spxrpc.go +++ b/pkg/spxrpc/spxrpc.go @@ -3,28 +3,35 @@ package spxrpc import ( "context" "net/http" + "time" "github.com/labstack/echo/v4" + "github.com/patrickmn/go-cache" "github.com/slok/go-http-metrics/middleware" echomiddleware "github.com/slok/go-http-metrics/middleware/echo" "github.com/streamplace/oatproxy/pkg/oatproxy" + "stream.place/streamplace/pkg/atproto" "stream.place/streamplace/pkg/config" "stream.place/streamplace/pkg/log" "stream.place/streamplace/pkg/model" ) type Server struct { - e *echo.Echo - cli *config.CLI - model model.Model + e *echo.Echo + cli *config.CLI + model model.Model + OGImageCache *cache.Cache + ATSync *atproto.ATProtoSynchronizer } -func NewServer(ctx context.Context, cli *config.CLI, model model.Model, op *oatproxy.OATProxy, mdlw middleware.Middleware) (*Server, error) { +func NewServer(ctx context.Context, cli *config.CLI, model model.Model, op *oatproxy.OATProxy, mdlw middleware.Middleware, atsync *atproto.ATProtoSynchronizer) (*Server, error) { e := echo.New() s := &Server{ - e: e, - cli: cli, - model: model, + e: e, + cli: cli, + model: model, + OGImageCache: cache.New(5*time.Minute, 10*time.Minute), // 5min TTL, 10min cleanup + ATSync: atsync, } e.Use(s.ErrorHandlingMiddleware()) e.Use(s.ContextPreservingMiddleware()) diff --git a/pkg/spxrpc/stubs.go b/pkg/spxrpc/stubs.go index 368a8101..c18676d6 100644 --- a/pkg/spxrpc/stubs.go +++ b/pkg/spxrpc/stubs.go @@ -245,6 +245,7 @@ func (s *Server) HandleComAtprotoSyncListRepos(c echo.Context) error { func (s *Server) RegisterHandlersPlaceStream(e *echo.Echo) error { e.GET("/xrpc/place.stream.graph.getFollowingUser", s.HandlePlaceStreamGraphGetFollowingUser) e.GET("/xrpc/place.stream.live.getLiveUsers", s.HandlePlaceStreamLiveGetLiveUsers) + e.GET("/xrpc/place.stream.live.getProfileCard", s.HandlePlaceStreamLiveGetProfileCard) e.GET("/xrpc/place.stream.live.getSegments", s.HandlePlaceStreamLiveGetSegments) return nil } @@ -289,6 +290,20 @@ func (s *Server) HandlePlaceStreamLiveGetLiveUsers(c echo.Context) error { return c.JSON(200, out) } +func (s *Server) HandlePlaceStreamLiveGetProfileCard(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandlePlaceStreamLiveGetProfileCard") + defer span.End() + id := c.QueryParam("id") + var out io.Reader + var handleErr error + // func (s *Server) handlePlaceStreamLiveGetProfileCard(ctx context.Context,id string) (io.Reader, error) + out, handleErr = s.handlePlaceStreamLiveGetProfileCard(ctx, id) + if handleErr != nil { + return handleErr + } + return c.Stream(200, "application/octet-stream", out) +} + func (s *Server) HandlePlaceStreamLiveGetSegments(c echo.Context) error { ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandlePlaceStreamLiveGetSegments") defer span.End() diff --git a/pkg/streamplace/livegetProfileCard.go b/pkg/streamplace/livegetProfileCard.go new file mode 100644 index 00000000..e5914d53 --- /dev/null +++ b/pkg/streamplace/livegetProfileCard.go @@ -0,0 +1,27 @@ +// Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. + +package streamplace + +// schema: place.stream.live.getProfileCard + +import ( + "bytes" + "context" + + "github.com/bluesky-social/indigo/lex/util" +) + +// LiveGetProfileCard calls the XRPC method "place.stream.live.getProfileCard". +// +// id: The DID or handle of the account. +func LiveGetProfileCard(ctx context.Context, c util.LexClient, id string) ([]byte, error) { + buf := new(bytes.Buffer) + + params := map[string]interface{}{} + params["id"] = id + if err := c.LexDo(ctx, util.Query, "", "place.stream.live.getProfileCard", params, nil, buf); err != nil { + return nil, err + } + + return buf.Bytes(), nil +}