ライブラリ・再生・削除を追加(Range 配信、パスの安全確認、共有ファイル名規則)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user