Compare commits

...

5 Commits

Author SHA1 Message Date
Loyalsoldier
a4da81130d Chore: update dependencies (#3068) 2025-12-17 01:05:10 +08:00
Loyalsoldier
4d45b17cd8 Chore: refine code (#3067) 2025-12-17 00:45:09 +08:00
Loyalsoldier
d8bd29ce92 Fix: incorrect lowercase for regexp rules (#3066) 2025-12-17 00:17:43 +08:00
Loyalsoldier
72eb885658 Refine: extract rule type (#3065) 2025-12-17 00:10:33 +08:00
风扇滑翔翼
93bfcfd142 Feat: check regexp before build (#3064)
Co-authored-by: Loyalsoldier <10487845+Loyalsoldier@users.noreply.github.com>
2025-12-16 23:40:25 +08:00
3 changed files with 56 additions and 33 deletions

8
go.mod
View File

@@ -1,14 +1,14 @@
module github.com/v2fly/domain-list-community module github.com/v2fly/domain-list-community
go 1.24 go 1.24.0
require ( require (
github.com/v2fly/v2ray-core/v5 v5.38.0 github.com/v2fly/v2ray-core/v5 v5.42.0
google.golang.org/protobuf v1.36.8 google.golang.org/protobuf v1.36.11
) )
require ( require (
github.com/adrg/xdg v0.5.3 // indirect github.com/adrg/xdg v0.5.3 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
golang.org/x/sys v0.34.0 // indirect golang.org/x/sys v0.38.0 // indirect
) )

16
go.sum
View File

@@ -8,13 +8,13 @@ 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/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/v2fly/v2ray-core/v5 v5.38.0 h1:DjpBP9dyzpFfCNGg+C6FnEkFDT3pfe29I0leYtNbKNY= github.com/v2fly/v2ray-core/v5 v5.42.0 h1:lyJrN3BDmu7lnVeMIlonAct8TSSHpIrNYP6/uYAbIBk=
github.com/v2fly/v2ray-core/v5 v5.38.0/go.mod h1:PHM3drDx9mbme6xE8fRZT979wNPHWCbCIPreAIqxqUw= github.com/v2fly/v2ray-core/v5 v5.42.0/go.mod h1:TyECxvulzqeaiFK14qNwhcoYOGnVmBkAj3Bs2MkVrNU=
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

51
main.go
View File

@@ -2,11 +2,11 @@ package main
import ( import (
"bufio" "bufio"
"errors"
"flag" "flag"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
"regexp"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@@ -22,6 +22,14 @@ var (
exportLists = flag.String("exportlists", "", "Lists to be flattened and exported in plaintext format, separated by ',' comma") exportLists = flag.String("exportlists", "", "Lists to be flattened and exported in plaintext format, separated by ',' comma")
) )
const (
RuleTypeDomain string = "domain"
RuleTypeFullDomain string = "full"
RuleTypeKeyword string = "keyword"
RuleTypeRegexp string = "regexp"
RuleTypeInclude string = "include"
)
type Entry struct { type Entry struct {
Type string Type string
Value string Value string
@@ -64,32 +72,41 @@ func (l *ParsedList) toProto() (*router.GeoSite, error) {
} }
for _, entry := range l.Entry { for _, entry := range l.Entry {
switch entry.Type { switch entry.Type {
case "domain": case RuleTypeDomain:
site.Domain = append(site.Domain, &router.Domain{ site.Domain = append(site.Domain, &router.Domain{
Type: router.Domain_RootDomain, Type: router.Domain_RootDomain,
Value: entry.Value, Value: entry.Value,
Attribute: entry.Attrs, Attribute: entry.Attrs,
}) })
case "regexp":
case RuleTypeRegexp:
// check regexp validity to avoid runtime error
_, err := regexp.Compile(entry.Value)
if err != nil {
return nil, fmt.Errorf("invalid regexp in list %s: %s", l.Name, entry.Value)
}
site.Domain = append(site.Domain, &router.Domain{ site.Domain = append(site.Domain, &router.Domain{
Type: router.Domain_Regex, Type: router.Domain_Regex,
Value: entry.Value, Value: entry.Value,
Attribute: entry.Attrs, Attribute: entry.Attrs,
}) })
case "keyword":
case RuleTypeKeyword:
site.Domain = append(site.Domain, &router.Domain{ site.Domain = append(site.Domain, &router.Domain{
Type: router.Domain_Plain, Type: router.Domain_Plain,
Value: entry.Value, Value: entry.Value,
Attribute: entry.Attrs, Attribute: entry.Attrs,
}) })
case "full":
case RuleTypeFullDomain:
site.Domain = append(site.Domain, &router.Domain{ site.Domain = append(site.Domain, &router.Domain{
Type: router.Domain_Full, Type: router.Domain_Full,
Value: entry.Value, Value: entry.Value,
Attribute: entry.Attrs, Attribute: entry.Attrs,
}) })
default: default:
return nil, errors.New("unknown domain type: " + entry.Type) return nil, fmt.Errorf("unknown domain type: %s", entry.Type)
} }
} }
return site, nil return site, nil
@@ -118,24 +135,30 @@ func removeComment(line string) string {
func parseDomain(domain string, entry *Entry) error { func parseDomain(domain string, entry *Entry) error {
kv := strings.Split(domain, ":") kv := strings.Split(domain, ":")
if len(kv) == 1 { if len(kv) == 1 {
entry.Type = "domain" entry.Type = RuleTypeDomain
entry.Value = strings.ToLower(kv[0]) entry.Value = strings.ToLower(kv[0])
return nil return nil
} }
if len(kv) == 2 { if len(kv) == 2 {
entry.Type = strings.ToLower(kv[0]) entry.Type = strings.ToLower(kv[0])
if strings.EqualFold(entry.Type, RuleTypeRegexp) {
entry.Value = kv[1]
} else {
entry.Value = strings.ToLower(kv[1]) entry.Value = strings.ToLower(kv[1])
}
return nil return nil
} }
return errors.New("Invalid format: " + domain) return fmt.Errorf("invalid format: %s", domain)
} }
func parseAttribute(attr string) (*router.Domain_Attribute, error) { func parseAttribute(attr string) (*router.Domain_Attribute, error) {
var attribute router.Domain_Attribute var attribute router.Domain_Attribute
if len(attr) == 0 || attr[0] != '@' { if len(attr) == 0 || attr[0] != '@' {
return &attribute, errors.New("invalid attribute: " + attr) return &attribute, fmt.Errorf("invalid attribute: %s", attr)
} }
// Trim attribute prefix `@` character // Trim attribute prefix `@` character
@@ -148,7 +171,7 @@ func parseAttribute(attr string) (*router.Domain_Attribute, error) {
attribute.Key = strings.ToLower(parts[0]) attribute.Key = strings.ToLower(parts[0])
intv, err := strconv.Atoi(parts[1]) intv, err := strconv.Atoi(parts[1])
if err != nil { if err != nil {
return &attribute, errors.New("invalid attribute: " + attr + ": " + err.Error()) return &attribute, fmt.Errorf("invalid attribute: %s: %v", attr, err)
} }
attribute.TypedValue = &router.Domain_Attribute_IntValue{IntValue: int64(intv)} attribute.TypedValue = &router.Domain_Attribute_IntValue{IntValue: int64(intv)}
} }
@@ -161,7 +184,7 @@ func parseEntry(line string) (Entry, error) {
var entry Entry var entry Entry
if len(parts) == 0 { if len(parts) == 0 {
return entry, errors.New("empty entry") return entry, fmt.Errorf("empty entry")
} }
if err := parseDomain(parts[0], &entry); err != nil { if err := parseDomain(parts[0], &entry); err != nil {
@@ -255,7 +278,7 @@ func ParseList(list *List, ref map[string]*List) (*ParsedList, error) {
newEntryList := make([]Entry, 0, len(entryList)) newEntryList := make([]Entry, 0, len(entryList))
hasInclude := false hasInclude := false
for _, entry := range entryList { for _, entry := range entryList {
if entry.Type == "include" { if entry.Type == RuleTypeInclude {
refName := strings.ToUpper(entry.Value) refName := strings.ToUpper(entry.Value)
if entry.Attrs != nil { if entry.Attrs != nil {
for _, attr := range entry.Attrs { for _, attr := range entry.Attrs {
@@ -267,7 +290,7 @@ func ParseList(list *List, ref map[string]*List) (*ParsedList, error) {
refList := ref[refName] refList := ref[refName]
if refList == nil { if refList == nil {
return nil, errors.New(entry.Value + " not found.") return nil, fmt.Errorf("list not found: %s", entry.Value)
} }
attrEntrys := createIncludeAttrEntrys(refList, attr) attrEntrys := createIncludeAttrEntrys(refList, attr)
if len(attrEntrys) != 0 { if len(attrEntrys) != 0 {
@@ -282,7 +305,7 @@ func ParseList(list *List, ref map[string]*List) (*ParsedList, error) {
pl.Inclusion[InclusionName] = true pl.Inclusion[InclusionName] = true
refList := ref[refName] refList := ref[refName]
if refList == nil { if refList == nil {
return nil, errors.New(entry.Value + " not found.") return nil, fmt.Errorf("list not found: %s", entry.Value)
} }
newEntryList = append(newEntryList, refList.Entry...) newEntryList = append(newEntryList, refList.Entry...)
} }