ytsync/namer/names.go

109 lines
2 KiB
Go
Raw Normal View History

2018-09-18 22:57:25 +02:00
package namer
2018-09-18 21:20:34 +02:00
import (
"crypto/md5"
"encoding/hex"
"fmt"
"regexp"
"strconv"
"strings"
"sync"
)
var claimNameRegexp = regexp.MustCompile(`[=&#:$@%?;、\\"/<>%{}|^~\x60[\]\s]`)
2018-09-18 21:20:34 +02:00
type Namer struct {
mu *sync.Mutex
names map[string]bool
}
func NewNamer() *Namer {
return &Namer{
mu: &sync.Mutex{},
names: make(map[string]bool),
}
}
2018-09-26 06:08:18 +02:00
func (n *Namer) SetNames(names map[string]bool) {
n.names = names
}
2018-09-18 21:20:34 +02:00
func (n *Namer) GetNextName(prefix string) string {
n.mu.Lock()
defer n.mu.Unlock()
attempt := 1
var name string
for {
name = getClaimNameFromTitle(prefix, attempt)
if _, exists := n.names[name]; !exists {
break
}
attempt++
}
//if for some reasons the title can't be converted in a valid claim name (too short or not latin) then we use a hash
attempt = 1
2018-09-18 21:20:34 +02:00
if len(name) < 2 {
2018-09-18 22:57:25 +02:00
sum := md5.Sum([]byte(prefix))
for {
name = fmt.Sprintf("%s-%d", hex.EncodeToString(sum[:])[:15], attempt)
if _, exists := n.names[name]; !exists {
break
}
attempt++
}
2018-09-18 21:20:34 +02:00
}
n.names[name] = true
return name
}
// TODO: clean this up some
func getClaimNameFromTitle(title string, attempt int) string {
suffix := ""
if attempt > 1 {
suffix = "-" + strconv.Itoa(attempt)
}
maxLen := 40 - len(suffix)
chunks := strings.Split(strings.ToLower(strings.Trim(claimNameRegexp.ReplaceAllString(title, "-"), "-")), "-")
2018-09-18 21:20:34 +02:00
name := chunks[0]
if len(name) > maxLen {
2021-03-17 16:40:37 +01:00
return truncateUnicode(name, maxLen) + suffix
2018-09-18 21:20:34 +02:00
}
for _, chunk := range chunks[1:] {
if chunk == "" {
continue
}
2018-09-18 21:20:34 +02:00
tmpName := name + "-" + chunk
if len(tmpName) > maxLen {
if len(name) < 20 {
name = truncateUnicode(tmpName, maxLen-len(name))
2018-09-18 21:20:34 +02:00
}
break
}
name = tmpName
}
return name + suffix
}
func truncateUnicode(name string, limit int) string {
reNameBlacklist := regexp.MustCompile(`(&|>|<|\/|:|\n|\r)*`)
name = reNameBlacklist.ReplaceAllString(name, "")
result := name
chars := 0
for i := range name {
if chars >= limit {
result = name[:i]
break
}
chars++
}
return result
}