62 lines
1.4 KiB
Go
62 lines
1.4 KiB
Go
package media
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
const maxComponentRunes = 80
|
|
const maxComponentBytes = 60
|
|
|
|
// RelativeVideoPath は worker と web が共有する保存先の相対パスを返す。
|
|
func RelativeVideoPath(seriesTitle, episodeTitle, episodeID string) string {
|
|
series := sanitizeComponent(seriesTitle)
|
|
episode := sanitizeComponent(episodeTitle)
|
|
id := sanitizeComponent(episodeID)
|
|
return filepath.Join(series, series+" "+episode+" ["+id+"].mp4")
|
|
}
|
|
|
|
func sanitizeComponent(value string) string {
|
|
var result []rune
|
|
lastReplacement := false
|
|
for _, r := range value {
|
|
invalid := unicode.IsControl(r) || strings.ContainsRune(`<>:"/\|?*`, r)
|
|
if invalid {
|
|
if !lastReplacement {
|
|
result = append(result, '_')
|
|
lastReplacement = true
|
|
}
|
|
continue
|
|
}
|
|
if unicode.IsSpace(r) {
|
|
r = ' '
|
|
}
|
|
result = append(result, r)
|
|
lastReplacement = false
|
|
}
|
|
clean := strings.Trim(string(result), " .")
|
|
if clean == "" || clean == "." || clean == ".." {
|
|
return "名称未設定"
|
|
}
|
|
runes := []rune(clean)
|
|
if len(runes) > maxComponentRunes {
|
|
runes = runes[:maxComponentRunes]
|
|
}
|
|
var limited []rune
|
|
bytes := 0
|
|
for _, r := range runes {
|
|
size := len(string(r))
|
|
if bytes+size > maxComponentBytes {
|
|
break
|
|
}
|
|
limited = append(limited, r)
|
|
bytes += size
|
|
}
|
|
clean = strings.Trim(string(limited), " .")
|
|
if clean == "" || clean == "." || clean == ".." {
|
|
return "名称未設定"
|
|
}
|
|
return clean
|
|
}
|