mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-30 03:36:37 +08:00
197 lines
5.4 KiB
Go
197 lines
5.4 KiB
Go
package service
|
|
|
|
import (
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
func parseSTRMTreeText(raw string) []string {
|
|
out, _ := parseSTRMTreeTextWithIgnored(raw)
|
|
return out
|
|
}
|
|
|
|
func parseSTRMTreeTextWithIgnored(raw string) ([]string, []string) {
|
|
var out []string
|
|
var ignored []string
|
|
stack := make([]string, 0, 8)
|
|
plainIndents := make([]int, 0, 8)
|
|
rootOffset := 0
|
|
for _, line := range strings.Split(raw, "\n") {
|
|
line = strings.TrimRight(line, " \t\r")
|
|
if strings.TrimSpace(line) == "" {
|
|
continue
|
|
}
|
|
if item, level, ok := parseSTRMTreeLine(line); ok {
|
|
plainIndents = plainIndents[:0]
|
|
level += rootOffset
|
|
stack = stack[:min(level, len(stack))]
|
|
if strmTreeItemIsVideoSource(item) {
|
|
out = append(out, strmTreeJoinedSource(stack, item))
|
|
continue
|
|
}
|
|
if strmTreeItemIsIgnoredFileSource(item) {
|
|
ignored = append(ignored, strmTreeJoinedSource(stack, item))
|
|
continue
|
|
}
|
|
stack = append(stack, item)
|
|
continue
|
|
}
|
|
if item, level, ok := parseSTRMTreeContinuationLine(line, len(plainIndents) > 0); ok {
|
|
plainIndents = plainIndents[:0]
|
|
level += rootOffset
|
|
stack = stack[:min(level, len(stack))]
|
|
if strmTreeItemIsVideoSource(item) {
|
|
out = append(out, path.Join(append(append([]string{}, stack...), item)...))
|
|
} else if strmTreeItemIsIgnoredFileSource(item) {
|
|
ignored = append(ignored, path.Join(append(append([]string{}, stack...), item)...))
|
|
}
|
|
continue
|
|
}
|
|
item := cleanSTRMTreeItemName(line)
|
|
if indent := strmTreePlainIndent(line); indent > 0 && !strings.ContainsAny(item, `/\`) {
|
|
for len(plainIndents) > 0 && indent <= plainIndents[len(plainIndents)-1] {
|
|
plainIndents = plainIndents[:len(plainIndents)-1]
|
|
}
|
|
level := rootOffset + len(plainIndents)
|
|
stack = stack[:min(level, len(stack))]
|
|
if strmTreeItemIsVideoSource(item) {
|
|
out = append(out, strmTreeJoinedSource(stack, item))
|
|
continue
|
|
}
|
|
if strmTreeItemIsIgnoredFileSource(item) {
|
|
ignored = append(ignored, strmTreeJoinedSource(stack, item))
|
|
continue
|
|
}
|
|
stack = append(stack, item)
|
|
plainIndents = append(plainIndents, indent)
|
|
continue
|
|
}
|
|
if strmTreeItemIsVideoSource(item) || strings.ContainsAny(item, `/\`) {
|
|
plainIndents = plainIndents[:0]
|
|
if strmTreeItemIsVideoSource(item) {
|
|
out = append(out, item)
|
|
} else if strmTreeItemIsIgnoredFileSource(item) {
|
|
ignored = append(ignored, item)
|
|
}
|
|
continue
|
|
}
|
|
if strmTreeItemIsIgnoredFileSource(item) {
|
|
ignored = append(ignored, item)
|
|
continue
|
|
}
|
|
stack = []string{item}
|
|
plainIndents = plainIndents[:0]
|
|
rootOffset = 1
|
|
}
|
|
return out, ignored
|
|
}
|
|
|
|
func parseSTRMTreeLine(line string) (string, int, bool) {
|
|
if idx := strings.Index(line, "──"); idx >= 0 {
|
|
prefix := line[:idx]
|
|
level := strmTreeIndentLevelWithWidth(prefix, 4)
|
|
item := cleanSTRMTreeItemName(strings.Trim(strings.TrimSpace(line[idx+len("──"):]), "─- "))
|
|
return item, level, item != ""
|
|
}
|
|
if idx := strings.Index(line, "─"); idx >= 0 {
|
|
prefix := line[:idx]
|
|
level := strmTreeIndentLevelWithWidth(prefix, 3)
|
|
item := cleanSTRMTreeItemName(strings.Trim(strings.TrimSpace(line[idx+len("─"):]), "─- "))
|
|
return item, level, item != ""
|
|
}
|
|
for _, marker := range []string{"|--", "+--", "`--"} {
|
|
if idx := strings.Index(line, marker); idx >= 0 {
|
|
item := cleanSTRMTreeItemName(line[idx+len(marker):])
|
|
return item, strmTreeIndentLevel(line[:idx]), item != ""
|
|
}
|
|
}
|
|
return "", 0, false
|
|
}
|
|
|
|
func parseSTRMTreeContinuationLine(line string, plainTreeActive bool) (string, int, bool) {
|
|
prefixLen := 0
|
|
hasGuide := false
|
|
for _, r := range line {
|
|
switch r {
|
|
case ' ', '\t', '│', '|':
|
|
if r == '│' || r == '|' {
|
|
hasGuide = true
|
|
}
|
|
prefixLen += len(string(r))
|
|
default:
|
|
if plainTreeActive && !hasGuide {
|
|
return "", 0, false
|
|
}
|
|
item := cleanSTRMTreeItemName(line[prefixLen:])
|
|
if item == "" || (!strmTreeItemIsVideoSource(item) && !strmTreeItemIsIgnoredFileSource(item)) {
|
|
return "", 0, false
|
|
}
|
|
return item, strmTreeIndentLevel(line[:prefixLen]), true
|
|
}
|
|
}
|
|
return "", 0, false
|
|
}
|
|
|
|
func strmTreeIndentLevel(prefix string) int {
|
|
return strmTreeIndentLevelWithWidth(prefix, 4)
|
|
}
|
|
|
|
func strmTreeIndentLevelWithWidth(prefix string, width int) int {
|
|
if prefix == "" {
|
|
return 0
|
|
}
|
|
if width <= 0 {
|
|
width = 4
|
|
}
|
|
verticals := strings.Count(prefix, "│") + strings.Count(prefix, "|")
|
|
runeLen := len([]rune(strings.ReplaceAll(strings.ReplaceAll(prefix, "│", " "), "|", " ")))
|
|
byWidth := 0
|
|
if runeLen > 0 {
|
|
byWidth = (runeLen - 1) / width
|
|
}
|
|
if verticals > byWidth {
|
|
return verticals
|
|
}
|
|
return byWidth
|
|
}
|
|
|
|
func strmTreePlainIndent(line string) int {
|
|
indent := 0
|
|
for _, r := range line {
|
|
switch r {
|
|
case ' ':
|
|
indent++
|
|
case '\t':
|
|
indent += 4
|
|
default:
|
|
return indent
|
|
}
|
|
}
|
|
return indent
|
|
}
|
|
|
|
func strmTreeItemIsVideoSource(item string) bool {
|
|
if strmTreeSourceIsVideo(item) {
|
|
return true
|
|
}
|
|
source := normalizeSTRMTreeSourceWithProvider(item, "openlist")
|
|
return source.Path != "" && strmTreeSourceIsVideo(source.Path)
|
|
}
|
|
|
|
func strmTreeItemIsIgnoredFileSource(item string) bool {
|
|
_, ok := strmTreeIgnoredFileLikeSource(item)
|
|
return ok
|
|
}
|
|
|
|
func strmTreeJoinedSource(stack []string, item string) string {
|
|
if strmTreeItemIsAbsoluteSource(item) {
|
|
return item
|
|
}
|
|
return path.Join(append(append([]string{}, stack...), item)...)
|
|
}
|
|
|
|
func strmTreeItemIsAbsoluteSource(item string) bool {
|
|
value := strings.ToLower(strings.TrimSpace(item))
|
|
return strings.Contains(value, "://") || strings.HasPrefix(value, "/api/")
|
|
}
|