fixed a new prescene layout
This commit is contained in:
Generated
+3
-1
@@ -3,7 +3,9 @@
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="GoModuleSettings" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ func main() {
|
||||
|
||||
err = dbase.Select(&titles,
|
||||
`SELECT title FROM theamok_mdb.external_sources
|
||||
WHERE type = 'prescene' AND releaser = ? limit 2000`, releaser)
|
||||
WHERE type = 'prescene' AND releaser = ?`, releaser)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -1,43 +1,42 @@
|
||||
module git.kplus.net.ua/yevhen/resource-scraper
|
||||
|
||||
go 1.26.2
|
||||
go 1.27
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/dromara/carbon/v2 v2.6.16
|
||||
github.com/dromara/carbon/v2 v2.6.17
|
||||
github.com/emersion/go-imap/v2 v2.0.0-beta.8
|
||||
github.com/go-chi/chi/v5 v5.2.5
|
||||
github.com/go-chi/chi/v5 v5.3.2
|
||||
github.com/go-chi/cors v1.2.2
|
||||
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
github.com/go-sql-driver/mysql v1.10.1
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
github.com/logrusorgru/aurora/v4 v4.0.0
|
||||
github.com/mewkiz/flac v1.0.13
|
||||
github.com/mewkiz/flac v1.0.14
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/spf13/viper v1.21.0
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f
|
||||
golang.org/x/net v0.49.0
|
||||
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba
|
||||
golang.org/x/net v0.59.0
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.2.0 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.3 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.5 // indirect
|
||||
github.com/emersion/go-message v0.18.2 // indirect
|
||||
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
|
||||
github.com/icza/bitio v1.1.0 // indirect
|
||||
github.com/mewkiz/pkg v0.0.0-20260331151047-10214ccde7de // indirect
|
||||
github.com/mewkiz/pkg v0.0.0-20260703220044-4fb89b18cc87 // indirect
|
||||
github.com/mewpkg/term v0.0.0-20241026122259-37a80af23985 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.4.3 // indirect
|
||||
github.com/sagikazarmark/locafero v0.12.0 // indirect
|
||||
github.com/spf13/afero v1.15.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/sys v0.40.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||
golang.org/x/sys v0.48.0 // indirect
|
||||
golang.org/x/text v0.42.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo=
|
||||
filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc=
|
||||
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
|
||||
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
|
||||
github.com/andybalholm/cascadia v1.3.5 h1:RLjq12WJy58dN6eCIQrz0bAGZkztHWsEPFxP53Y7Ms8=
|
||||
github.com/andybalholm/cascadia v1.3.5/go.mod h1:BLRmbRjpEtNKieZOCCvYj4RqN+KRA41GBe/5O+G93kM=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dromara/carbon/v2 v2.6.16 h1:AbxrnW1kJhR3KHdS8G96NFmxDwPFyre+t+xSiJIUD1I=
|
||||
github.com/dromara/carbon/v2 v2.6.16/go.mod h1:NGo3reeV5vhWCYWcSqbJRZm46MEwyfYI5EJRdVFoLJo=
|
||||
github.com/dromara/carbon/v2 v2.6.17 h1:QL1LVcp5A/NQtIPbc1vrL9qIXxPNWnaDOBaFlmP1iDg=
|
||||
github.com/dromara/carbon/v2 v2.6.17/go.mod h1:NGo3reeV5vhWCYWcSqbJRZm46MEwyfYI5EJRdVFoLJo=
|
||||
github.com/emersion/go-imap/v2 v2.0.0-beta.8 h1:5IXZK1E33DyeP526320J3RS7eFlCYGFgtbrfapqDPug=
|
||||
github.com/emersion/go-imap/v2 v2.0.0-beta.8/go.mod h1:dhoFe2Q0PwLrMD7oZw8ODuaD0vLYPe5uj2wcOMnvh48=
|
||||
github.com/emersion/go-message v0.18.2 h1:rl55SQdjd9oJcIoQNhubD2Acs1E6IzlZISRTK7x/Lpg=
|
||||
@@ -15,17 +15,17 @@ github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 h1:oP4q0fw+fOSWn3
|
||||
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
|
||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
|
||||
github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/go-chi/chi/v5 v5.3.2 h1:5YQkICvTCSZ25hoRsyJazN0scjzKGiu4VAUc7H1o1nY=
|
||||
github.com/go-chi/chi/v5 v5.3.2/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
|
||||
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c h1:wpkoddUomPfHiOziHZixGO5ZBS73cKqVzZipfrLmO1w=
|
||||
github.com/go-shiori/dom v0.0.0-20230515143342-73569d674e1c/go.mod h1:oVDCh3qjJMLVUSILBRwrm+Bc6RNXGZYtoh9xdvf1ffM=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo=
|
||||
github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||
github.com/go-sql-driver/mysql v1.10.1 h1:arlSnNLq6a5yxGxV7qg9lF4j0C+KwD6NbQyKr9QL6ME=
|
||||
github.com/go-sql-driver/mysql v1.10.1/go.mod h1:M+cqaI7+xxXGG9swrdeUIoPG3Y3KCkF0pZej+SK+nWk=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro=
|
||||
github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
|
||||
@@ -50,14 +50,14 @@ github.com/logrusorgru/aurora/v4 v4.0.0 h1:sRjfPpun/63iADiSvGGjgA1cAYegEWMPCJdUp
|
||||
github.com/logrusorgru/aurora/v4 v4.0.0/go.mod h1:lP0iIa2nrnT/qoFXcOZSrZQpJ1o6n2CUf/hyHi2Q4ZQ=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mewkiz/flac v1.0.13 h1:6wF8rRQKBFW159Daqx6Ro7K5ZnlVhHUKfS5aTsC4oXs=
|
||||
github.com/mewkiz/flac v1.0.13/go.mod h1:HfPYDA+oxjyuqMu2V+cyKcxF51KM6incpw5eZXmfA6k=
|
||||
github.com/mewkiz/pkg v0.0.0-20260331151047-10214ccde7de h1:tVseKKgTIPOo8L0gFK4qX+kqyINtWncwER/t1n2im1A=
|
||||
github.com/mewkiz/pkg v0.0.0-20260331151047-10214ccde7de/go.mod h1:omNJr4dHOKbrBeoY/idmLDFw8OIdDUUZvj3uB1cJxwA=
|
||||
github.com/mewkiz/flac v1.0.14 h1:hyRGAM8NCKznoPmIi9zz2jyO+nfmxY2ErqBnHZ+gxh4=
|
||||
github.com/mewkiz/flac v1.0.14/go.mod h1:HfPYDA+oxjyuqMu2V+cyKcxF51KM6incpw5eZXmfA6k=
|
||||
github.com/mewkiz/pkg v0.0.0-20260703220044-4fb89b18cc87 h1:fpWNLIg7nX2f+D+6ZveQ5hfkTjq5WgMBtYbz5Nb1w0Y=
|
||||
github.com/mewkiz/pkg v0.0.0-20260703220044-4fb89b18cc87/go.mod h1:wohiqwTwXA5twjDES74xIJLGjAxo3/0pHSbTXLbSDW8=
|
||||
github.com/mewpkg/term v0.0.0-20241026122259-37a80af23985 h1:h8O1byDZ1uk6RUXMhj1QJU3VXFKXHDZxr4TXRPGeBa8=
|
||||
github.com/mewpkg/term v0.0.0-20241026122259-37a80af23985/go.mod h1:uiPmbdUbdt1NkGApKl7htQjZ8S7XaGUAVulJUJ9v6q4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pelletier/go-toml/v2 v2.4.3 h1:GTRvJQutkOSftxIFD5xw9aepkYNuPWmVJpffdDPYVpY=
|
||||
github.com/pelletier/go-toml/v2 v2.4.3/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
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/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
@@ -77,81 +77,45 @@ github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
||||
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
|
||||
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
|
||||
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba h1:Ck8QetSgk912qxWLMCKxd0in+aiyBQyDSMae6e/xmpU=
|
||||
golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba/go.mod h1:50RgIsmK7OwqzTTeqcSXQW8SswW0o8fRcDxmqGluJ8E=
|
||||
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/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.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
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/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
|
||||
golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
|
||||
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.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
|
||||
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/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||
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.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
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/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
|
||||
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
|
||||
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/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"git.kplus.net.ua/yevhen/resource-scraper/internal/releaseparser"
|
||||
)
|
||||
|
||||
@@ -58,31 +56,31 @@ func Parse(raw string) releaseparser.ParsedRelease {
|
||||
return result
|
||||
}
|
||||
|
||||
// Where the dictionary-driven tail zone begins: after the resolved
|
||||
// Artist/Title core (2 tokens by default, 3 with an artist dictionary hit).
|
||||
// Left core boundary: after the resolved Artist (2 tokens by default,
|
||||
// 3 with an artist dictionary hit, or fixed by an override).
|
||||
start := 2
|
||||
|
||||
// Level 1: exact-lookup override table fixes Artist/Title only;
|
||||
// the tail zone is parsed as usual below.
|
||||
// the tail zone is parsed as usual below. The override is
|
||||
// authoritative about the core: leftover tokens are plain unknowns,
|
||||
// not part of the title.
|
||||
if o, ok := Profile.Overrides[result.Raw]; ok {
|
||||
result.Artist, result.Title = o.Artist, o.Title
|
||||
start = overrideCoreLength(tokens, o)
|
||||
}
|
||||
|
||||
// Level 2: artist dictionary — "[0]-[1]" whitelisted as a hyphenated
|
||||
// artist shifts the core by one token.
|
||||
switch {
|
||||
case result.Artist != "":
|
||||
// An override already fixed the core — leave it alone.
|
||||
case len(tokens) >= 3 &&
|
||||
Profile.ArtistTokens[strings.ToUpper(tokens[0]+"-"+tokens[1])]:
|
||||
result.Artist = tokens[0] + "-" + tokens[1]
|
||||
result.Title = tokens[2]
|
||||
start = 3
|
||||
default:
|
||||
result.Artist = tokens[0]
|
||||
if len(tokens) > 1 {
|
||||
result.Title = tokens[1]
|
||||
// Level 2: artist dictionary — a hyphenated artist may span ANY number
|
||||
// of leading tokens ("Shadu-Nar-Mattaru" = 3). The LONGEST whitelisted
|
||||
// prefix wins; the title is the token right after it. At least one
|
||||
// title token and one tail token must remain.
|
||||
artistDict := false
|
||||
if result.Artist == "" {
|
||||
for k := len(tokens) - 2; k >= 2; k-- {
|
||||
if Profile.ArtistTokens[strings.ToUpper(strings.Join(tokens[:k], "-"))] {
|
||||
artistDict = true
|
||||
start = k + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +91,41 @@ func Parse(raw string) releaseparser.ParsedRelease {
|
||||
end = len(tokens) - 2
|
||||
}
|
||||
|
||||
// Right core boundary: the first dictionary-known token after the
|
||||
// resolved artist. The boundary is contextual, but the title itself
|
||||
// stays a single token ([1], or [2] with an artist dictionary hit).
|
||||
// Unknown tokens inside the core region ([start .. tailStart)) are
|
||||
// REPORTED in UnknownTokens — never eaten, never glued into the title.
|
||||
tailStart := end
|
||||
for i := start; i < end; i++ {
|
||||
if isKnownToken(tokens[i]) {
|
||||
tailStart = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve Artist/Title from the core unless the override already did.
|
||||
if result.Artist == "" {
|
||||
if artistDict {
|
||||
// The artist spans tokens [0 .. start-2]; re-join them.
|
||||
result.Artist = strings.Join(tokens[:start-1], "-")
|
||||
} else {
|
||||
result.Artist = tokens[0]
|
||||
}
|
||||
if len(tokens) > start-1 {
|
||||
result.Title = tokens[start-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Core-region leftovers (e.g. the rest of a wildcards title after an
|
||||
// override, or a hyphenated title fragment without an artist entry):
|
||||
// visible in UnknownTokens for review.
|
||||
for _, tok := range tokens[start:tailStart] {
|
||||
result.UnknownTokens = append(result.UnknownTokens, tok)
|
||||
}
|
||||
|
||||
// Level 3: dictionary-driven tail zone, starting after the resolved core.
|
||||
parseTailZone(start, tokens[start:end], &result)
|
||||
parseTailZone(tokens[tailStart:end], &result)
|
||||
|
||||
score(&result)
|
||||
return result
|
||||
@@ -160,12 +191,24 @@ func catalogNumber(token string) string {
|
||||
return token[1 : len(token)-1]
|
||||
}
|
||||
|
||||
// isKnownToken reports whether the token belongs to the tail zone: it
|
||||
// matches one of the profile dictionaries or is a parenthesized catalogue
|
||||
// number. The first such token after the core marks the right core
|
||||
// boundary.
|
||||
func isKnownToken(tok string) bool {
|
||||
up := strings.ToUpper(tok)
|
||||
return Profile.FormatTokens[up] || Profile.SourceTokens[up] ||
|
||||
Profile.BitDepthTokens[up] || Profile.ResolutionTokens[up] ||
|
||||
Profile.EditionTokens[up] || Profile.LanguageMarkers[up] ||
|
||||
catalogNumber(tok) != ""
|
||||
}
|
||||
|
||||
// parseTailZone resolves middle-zone tokens against the dictionaries.
|
||||
// The first match wins for each field; catalogue numbers are recognized
|
||||
// from parenthesized tokens, and anything unrecognized is appended to
|
||||
// UnknownTokens so that it can be reviewed and curated into a dictionary.
|
||||
func parseTailZone(start int, zone []string, result *releaseparser.ParsedRelease) {
|
||||
for i, tok := range zone {
|
||||
func parseTailZone(zone []string, result *releaseparser.ParsedRelease) {
|
||||
for _, tok := range zone {
|
||||
up := strings.ToUpper(tok)
|
||||
switch {
|
||||
case Profile.FormatTokens[up]:
|
||||
@@ -197,13 +240,6 @@ func parseTailZone(start int, zone []string, result *releaseparser.ParsedRelease
|
||||
default:
|
||||
if cat := catalogNumber(tok); cat != "" && result.CatalogNo == "" {
|
||||
result.CatalogNo = cat
|
||||
} else if hasLaterKnownToken(zone, i) {
|
||||
// suspected title continuation: the core is probably longer
|
||||
// than 2 tokens. Not eaten, not unknown — review section.
|
||||
result.TitleExtra = append(result.TitleExtra, tok)
|
||||
if !slices.Contains(result.Warnings, "suspected title continuation") {
|
||||
result.Warnings = append(result.Warnings, "suspected title continuation")
|
||||
}
|
||||
} else {
|
||||
result.UnknownTokens = append(result.UnknownTokens, tok)
|
||||
}
|
||||
@@ -220,20 +256,6 @@ func applyType(tok string, result *releaseparser.ParsedRelease) {
|
||||
}
|
||||
}
|
||||
|
||||
// hasLaterKnownToken reports whether any token after index i in the zone
|
||||
// matches one of the profile dictionaries.
|
||||
func hasLaterKnownToken(zone []string, i int) bool {
|
||||
for _, later := range zone[i+1:] {
|
||||
up := strings.ToUpper(later)
|
||||
if Profile.FormatTokens[up] || Profile.SourceTokens[up] ||
|
||||
Profile.BitDepthTokens[up] || Profile.ResolutionTokens[up] ||
|
||||
Profile.EditionTokens[up] || Profile.LanguageMarkers[up] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// overrideCoreLength returns the number of leading tokens covered by the
|
||||
// override's Artist and Title (each may span several hyphen-separated
|
||||
// tokens), falling back to the default 2-token core when the raw tokens
|
||||
|
||||
@@ -38,23 +38,20 @@ func TestParseEditionAndDemo(t *testing.T) {
|
||||
|
||||
func TestParseArtistWithHyphen(t *testing.T) {
|
||||
// Artist сам містить дефіс, але Ultra-Violence ще не в словнику:
|
||||
// модель [0]/[1] лишається, а All_My_Life (за ним ідуть словникові
|
||||
// маркери) — suspected title continuation, не unknown.
|
||||
// core контекстуальний — все між артистом і першим словниковим
|
||||
// маркером (EP) є назвою, зібраною назад через "-".
|
||||
r := Parse("Ultra-Violence-All_My_Life-EP-16BIT-WEB-FLAC-2026-MOONBLOOD")
|
||||
if r.Artist != "Ultra" || r.Title != "Violence" {
|
||||
t.Errorf("Artist/Title = %q/%q, want Ultra / Violence", r.Artist, r.Title)
|
||||
if r.Artist != "Ultra" {
|
||||
t.Errorf("Artist = %q, want Ultra", r.Artist)
|
||||
}
|
||||
if r.Title != "Violence" {
|
||||
t.Errorf("Title = %q, want Violence", r.Title)
|
||||
}
|
||||
if r.Edition != "EP" || r.BitDepth != "16BIT" || r.Source != "WEB" || r.Year != 2026 {
|
||||
t.Errorf("tail fields wrong: %+v", r)
|
||||
}
|
||||
if len(r.TitleExtra) != 1 || r.TitleExtra[0] != "All_My_Life" {
|
||||
t.Errorf("TitleExtra = %v, want [All_My_Life]", r.TitleExtra)
|
||||
}
|
||||
if !contains(r.Warnings, "suspected title continuation") {
|
||||
t.Errorf("Warnings = %v, want suspected title continuation", r.Warnings)
|
||||
}
|
||||
if len(r.UnknownTokens) != 0 {
|
||||
t.Errorf("UnknownTokens = %v, want empty", r.UnknownTokens)
|
||||
if len(r.UnknownTokens) != 1 || r.UnknownTokens[0] != "All_My_Life" {
|
||||
t.Errorf("UnknownTokens = %v, want [All_My_Life]", r.UnknownTokens)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,22 +144,23 @@ func TestParseUnknownTailTokenReported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSuspectedTitleContinuation(t *testing.T) {
|
||||
// Невідомий токен МІЖ title-зоною і хвостом (за ним далі йдуть
|
||||
// словникові маркери) → не UnknownTokens, а TitleExtra + warning.
|
||||
r := Parse("Artist-Some_Title-SPLIT-FOO-16BIT-WEB-FLAC-2025-MOONBLOOD")
|
||||
if len(r.TitleExtra) != 1 || r.TitleExtra[0] != "FOO" {
|
||||
t.Errorf("TitleExtra = %v, want [FOO]", r.TitleExtra)
|
||||
func TestParseContextualCoreAbsorbsTitleTail(t *testing.T) {
|
||||
// Права межа core контекстуальна (перший словниковий маркер), але
|
||||
// невідомі токени всередині core-зони — в UnknownTokens, не з'їдаються.
|
||||
r := Parse("Artist-Some_Title-Part_Two-Part_Three-16BIT-WEB-FLAC-2025-MOONBLOOD")
|
||||
if r.Artist != "Artist" {
|
||||
t.Errorf("Artist = %q, want Artist", r.Artist)
|
||||
}
|
||||
if len(r.UnknownTokens) != 0 {
|
||||
t.Errorf("UnknownTokens = %v, want empty", r.UnknownTokens)
|
||||
if r.Title != "Some_Title" {
|
||||
t.Errorf("Title = %q, want Some_Title", r.Title)
|
||||
}
|
||||
if !contains(r.Warnings, "suspected title continuation") {
|
||||
t.Errorf("Warnings = %v, want suspected title continuation", r.Warnings)
|
||||
}
|
||||
if r.Edition != "SPLIT" || r.BitDepth != "16BIT" || r.Source != "WEB" || r.Year != 2025 {
|
||||
if r.BitDepth != "16BIT" || r.Source != "WEB" || r.Format != "FLAC" || r.Year != 2025 {
|
||||
t.Errorf("tail fields wrong: %+v", r)
|
||||
}
|
||||
if len(r.UnknownTokens) != 2 || r.UnknownTokens[0] != "Part_Two" ||
|
||||
r.UnknownTokens[1] != "Part_Three" {
|
||||
t.Errorf("UnknownTokens = %v, want [Part_Two Part_Three]", r.UnknownTokens)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCoreTokensNeverReported(t *testing.T) {
|
||||
@@ -282,9 +280,8 @@ func TestParseCatalogNumberWithDotAndRoman(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseSplitKeepsParensAndSplitsTitles(t *testing.T) {
|
||||
// [1]=Title (фіксовано), а Evolution — не словниковий токен у середині:
|
||||
// за ним ідуть словникові маркери → suspected title continuation.
|
||||
// (SMG409) — катало, залишається каталом.
|
||||
// Evolution — не словниковий токен у core-зоні → в UnknownTokens,
|
||||
// не з'їдається. (SMG409) — катало, перший відомий маркер.
|
||||
r := Parse("Ferosity-De-Evolution-(SMG409)-CD-FLAC-2025-86D")
|
||||
if r.CatalogNo != "SMG409" {
|
||||
t.Errorf("CatalogNo = %q, want SMG409", r.CatalogNo)
|
||||
@@ -292,11 +289,8 @@ func TestParseSplitKeepsParensAndSplitsTitles(t *testing.T) {
|
||||
if r.Artist != "Ferosity" || r.Title != "De" {
|
||||
t.Errorf("Artist/Title = %q/%q, want Ferosity / De", r.Artist, r.Title)
|
||||
}
|
||||
if len(r.TitleExtra) != 1 || r.TitleExtra[0] != "Evolution" {
|
||||
t.Errorf("TitleExtra = %v, want [Evolution]", r.TitleExtra)
|
||||
}
|
||||
if len(r.UnknownTokens) != 0 {
|
||||
t.Errorf("UnknownTokens = %v, want empty", r.UnknownTokens)
|
||||
if len(r.UnknownTokens) != 1 || r.UnknownTokens[0] != "Evolution" {
|
||||
t.Errorf("UnknownTokens = %v, want [Evolution]", r.UnknownTokens)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,18 +357,14 @@ func TestParseCompoundEditionRecognized(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseMixedCaseTitleNeverReported(t *testing.T) {
|
||||
// [1]=Title (один токен). Хвіст назви (_ і Sky_Burial) — не словник,
|
||||
// але за ним ідуть словникові маркери → suspected title continuation,
|
||||
// не UnknownTokens.
|
||||
// Хвіст назви (_Sky_Burial) — не словник, але він ДО першого маркера
|
||||
// (катало (RTM103)) → частина назви, не UnknownTokens.
|
||||
r := Parse("Enthrallment-Against_the_Will_to_Live_-_Sky_Burial-(RTM103)-CD-FLAC-2021-86D")
|
||||
if r.Artist != "Enthrallment" || r.Title != "Against_the_Will_to_Live_" {
|
||||
t.Errorf("Artist/Title = %q/%q", r.Artist, r.Title)
|
||||
}
|
||||
if len(r.UnknownTokens) != 0 {
|
||||
t.Errorf("UnknownTokens = %v, want empty", r.UnknownTokens)
|
||||
}
|
||||
if len(r.TitleExtra) != 1 || r.TitleExtra[0] != "_Sky_Burial" {
|
||||
t.Errorf("TitleExtra = %v, want [_Sky_Burial]", r.TitleExtra)
|
||||
if len(r.UnknownTokens) != 1 || r.UnknownTokens[0] != "_Sky_Burial" {
|
||||
t.Errorf("UnknownTokens = %v, want [_Sky_Burial]", r.UnknownTokens)
|
||||
}
|
||||
if r.CatalogNo != "RTM103" {
|
||||
t.Errorf("CatalogNo = %q, want RTM103", r.CatalogNo)
|
||||
@@ -426,10 +416,30 @@ func TestParseArtistDictionaryCoversReleases(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseArtistDictionaryMultiTokenArtist(t *testing.T) {
|
||||
// artists.txt: "Shadu-Nar-Mattaru" — артист з ТРЬОХ токенів.
|
||||
// Найдовший словниковий префікс виграє: Artist = 3 токени,
|
||||
// Title = наступний токен, хвіст парситься як завжди.
|
||||
r := Parse("Shadu-Nar-Mattaru-On_Pathways_Macabre-24BIT-WEB-FLAC-2023-MOONBLOOD")
|
||||
if r.Artist != "Shadu-Nar-Mattaru" {
|
||||
t.Errorf("Artist = %q, want Shadu-Nar-Mattaru", r.Artist)
|
||||
}
|
||||
if r.Title != "On_Pathways_Macabre" {
|
||||
t.Errorf("Title = %q, want On_Pathways_Macabre", r.Title)
|
||||
}
|
||||
if r.BitDepth != "24BIT" || r.Source != "WEB" || r.Format != "FLAC" || r.Year != 2023 {
|
||||
t.Errorf("tail fields wrong: %+v", r)
|
||||
}
|
||||
if len(r.UnknownTokens) != 0 || len(r.TitleExtra) != 0 || len(r.Warnings) != 0 {
|
||||
t.Errorf("Unknown=%v Extra=%v Warnings=%v, want empty",
|
||||
r.UnknownTokens, r.TitleExtra, r.Warnings)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseOverrideWinsOverPositionalModel(t *testing.T) {
|
||||
// overrides.txt (найвищий пріоритет): точний lookup по Raw
|
||||
// фіксує Artist/Title; хвіст парситься як завжди.
|
||||
raw := "Milicia_Oscura-Anti-Cristo-ES-16BIT-WEB-FLAC-2024-GRAVEWAVE"
|
||||
raw := "Milicia_Oscura-Anti-Cristo-ES-16BIT-WEB-FLAC-2013-MOONBLOOD"
|
||||
r := Parse(raw)
|
||||
if r.Artist != "Milicia_Oscura" {
|
||||
t.Errorf("Artist = %q, want Milicia_Oscura", r.Artist)
|
||||
@@ -438,7 +448,7 @@ func TestParseOverrideWinsOverPositionalModel(t *testing.T) {
|
||||
t.Errorf("Title = %q, want Anti-Cristo", r.Title)
|
||||
}
|
||||
if r.Language != "ES" || r.BitDepth != "16BIT" || r.Source != "WEB" ||
|
||||
r.Format != "FLAC" || r.Year != 2024 || r.Group != "GRAVEWAVE" {
|
||||
r.Format != "FLAC" || r.Year != 2013 || r.Group != "MOONBLOOD" {
|
||||
t.Errorf("tail fields wrong: %+v", r)
|
||||
}
|
||||
if len(r.UnknownTokens) != 0 || len(r.TitleExtra) != 0 || len(r.Warnings) != 0 {
|
||||
|
||||
@@ -85,16 +85,25 @@ func parseUrl(endpoint string, db *sqlx.DB) ([]model.ExternalSources, error) {
|
||||
}
|
||||
var validID = regexp.MustCompile(`-\d+\/$`)
|
||||
|
||||
for i, item := range dom.QuerySelectorAll(doc, ".post.type-post.category-flac.category-music") {
|
||||
for i, item := range dom.QuerySelectorAll(doc, "li.row") {
|
||||
var es model.ExternalSources
|
||||
columns := []string{"`type`", "type_id", "title", "eXsource", "releaser", "created"}
|
||||
|
||||
// TypeId тепер напряму з data-id на <li>, без regex по class
|
||||
idAttr := dom.GetAttribute(item, "data-id")
|
||||
es.TypeId, _ = strconv.Atoi(idAttr)
|
||||
|
||||
title := dom.QuerySelector(item, ".title")
|
||||
if title != nil {
|
||||
anchor := dom.QuerySelector(title, "h1 > a")
|
||||
anchor := dom.QuerySelector(title, "a")
|
||||
if anchor != nil {
|
||||
es.Type = constant.ScopePrescene
|
||||
es.Title = dom.GetAttribute(anchor, "title")
|
||||
|
||||
titleSpan := dom.QuerySelector(anchor, "span.title-start")
|
||||
if titleSpan != nil {
|
||||
es.Title = dom.TextContent(titleSpan)
|
||||
}
|
||||
|
||||
if es.Title == "Auto Draft" {
|
||||
slog.Info("Skipped", "title", es.Title)
|
||||
continue
|
||||
@@ -123,17 +132,13 @@ func parseUrl(endpoint string, db *sqlx.DB) ([]model.ExternalSources, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
localtime := dom.QuerySelector(title, "small > span.localtime")
|
||||
localtime := dom.QuerySelector(item, "span.localtime")
|
||||
if localtime != nil {
|
||||
lc := dom.GetAttribute(localtime, "data-lttime")
|
||||
es.Created = carbon.Parse(lc, "Europe/Kyiv")
|
||||
}
|
||||
}
|
||||
|
||||
cls := dom.GetAttribute(item, "class")
|
||||
pattern := regexp.MustCompile(`(?s)^post-(\d+)\spost`)
|
||||
es.TypeId, _ = strconv.Atoi(pattern.FindStringSubmatch(cls)[1])
|
||||
|
||||
esModel := table.ExternalSources{Columns: columns}
|
||||
entry := esModel.InsertOnDuplicate(es, db)
|
||||
entries = append(entries, entry)
|
||||
|
||||
Reference in New Issue
Block a user