diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/ass.go | 446 | ||||
| -rw-r--r-- | lib/go.mod | 17 | ||||
| -rw-r--r-- | lib/mkv.go | 297 | ||||
| -rw-r--r-- | lib/shared.go | 54 | ||||
| -rw-r--r-- | lib/utils.go | 220 |
5 files changed, 0 insertions, 1034 deletions
diff --git a/lib/ass.go b/lib/ass.go deleted file mode 100644 index 7482ac8..0000000 --- a/lib/ass.go +++ /dev/null @@ -1,446 +0,0 @@ -package mkvlib - -import ( - "encoding/binary" - "fmt" - "github.com/antchfx/xmlquery" - "github.com/asticode/go-astisub" - "io" - "log" - "os" - "path" - "regexp" - "strconv" - "strings" - "sync" - "time" -) - -const ( - ttx = "ttx" - pyftsubset = "pyftsubset" -) - -type fontInfo struct { - file string - str string - index string - oldName string - newName string - ttx string - sFont string -} - -type assProcessor struct { - files []string - _fonts string - output string - m map[string]*fontInfo - fonts []string - sFonts []string - subtitles map[string]string -} - -func (self *assProcessor) parse() bool { - ec := 0 - self.subtitles = make(map[string]string) - for _, file := range self.files { - f, err := openFile(file, true, false) - if err != nil { - ec++ - } else { - data, _ := io.ReadAll(f) - str := string(data) - if err == nil { - self.subtitles[file] = str - } else { - ec++ - } - } - if ec > 0 { - log.Printf(`Failed to read the ass file: "%s"`, file) - } - } - if ec == 0 { - reg, _ := regexp.Compile(`\{?\\fn@?([^\r\n\\\}]+)[\\\}]`) - m := make(map[string]map[rune]bool) - for k, v := range self.subtitles { - subtitle, err := astisub.ReadFromSSA(strings.NewReader(v)) - if err != nil { - ec++ - log.Printf(`Failed to read the ass file: "%s"`, k) - continue - } - for _, item := range subtitle.Items { - for _, _item := range item.Lines { - for _, __item := range _item.Items { - name := item.Style.InlineStyle.SSAFontName - if __item.InlineStyle != nil { - arr := reg.FindStringSubmatch(__item.InlineStyle.SSAEffect) - if len(arr) > 1 { - name = arr[1] - } - } - if strings.HasPrefix(name, "@") && len(name) > 1 { - name = name[1:] - } - if m[name] == nil { - m[name] = make(map[rune]bool) - } - str := __item.Text - for _, char := range str { - m[name][char] = true - } - } - } - } - } - self.m = make(map[string]*fontInfo) - reg, _ = regexp.Compile("[A-Za-z0-9]]") - for k, v := range m { - str := "" - for _k, _ := range v { - str += string(_k) - } - str = strings.TrimSpace(str) - if str != "" { - str = reg.ReplaceAllString(str, "") - str += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - reg, _ = regexp.Compile("[1234567890]") - if reg.MatchString(str) { - str = reg.ReplaceAllString(str, "") - str += "1234567890" - } - self.m[k] = new(fontInfo) - self.m[k].str = str - self.m[k].oldName = k - } - } - } - if len(self.m) == 0 { - log.Printf(`Not Found item in the ass file(s): "%d"`, len(self.files)) - } - return ec == 0 -} - -func (self *assProcessor) getTTCCount(file string) int { - f, err := openFile(file, true, false) - if err == nil { - defer func() { _ = f.Close() }() - data := make([]byte, 4) - if n, err := f.ReadAt(data, 8); err == nil && n == 4 { - return int(binary.BigEndian.Uint32(data)) - } - } - return 0 -} - -func (self *assProcessor) dumpFont(file string, full bool) bool { - ok := false - count := 1 - _, n, _, _ := splitPath(file) - if strings.HasSuffix(file, ".ttc") { - count = self.getTTCCount(file) - if count < 1 { - log.Printf(`Failed to get the ttc font count: "%s".`, n) - return ok - } - } - for i := 0; i < count; i++ { - fn := fmt.Sprintf("%s_%d.ttx", file, i) - args := make([]string, 0) - args = append(args, "-q") - args = append(args, "-f") - args = append(args, "-y", strconv.Itoa(i)) - args = append(args, "-o", fn) - if !full { - args = append(args, "-t", "name") - } - args = append(args, file) - if p, err := newProcess(nil, nil, nil, "", ttx, args...); err == nil { - s, err := p.Wait() - ok = err == nil && s.ExitCode() == 0 - } - if !ok { - log.Printf(`Failed to dump font(%t): "%s"[%d].`, full, n, i) - } - } - return ok -} - -func (self *assProcessor) dumpFonts(files []string, full bool) bool { - ok := 0 - l := len(files) - wg := new(sync.WaitGroup) - wg.Add(l) - m := new(sync.Mutex) - for _, item := range files { - go func(_item string) { - _ok := self.dumpFont(_item, full) - if _ok { - m.Lock() - ok++ - m.Unlock() - } - wg.Done() - }(item) - } - wg.Wait() - return ok == l -} - -func (self *assProcessor) getFontName(p string) []string { - f, err := openFile(p, true, false) - if err == nil { - defer func() { _ = f.Close() }() - names := make([]string, 0) - if xml, err := xmlquery.Parse(f); err == nil { - for _, v := range xml.SelectElements(`ttFont/name/namerecord[@platformID=3]`) { - id := v.SelectAttr("nameID") - name := strings.TrimSpace(v.FirstChild.Data) - switch id { - case "1": - names = append(names, name) - break - case "4": - names = append(names, name) - break - } - } - } - return names - } - return nil -} - -func (self *assProcessor) getFontsName() map[string][]string { - files, _ := findPath(self._fonts, `\.ttx$`) - l := len(files) - wg := new(sync.WaitGroup) - wg.Add(l) - m := new(sync.Mutex) - _m := make(map[string][]string) - for _, item := range files { - go func(_item string) { - names := self.getFontName(_item) - if len(names) > 0 { - m.Lock() - _m[_item] = names - m.Unlock() - } - wg.Done() - }(item) - } - wg.Wait() - return _m -} - -func (self *assProcessor) matchFonts() bool { - if !self.dumpFonts(self.fonts, false) { - return false - } - m := self.getFontsName() - if len(m) > 0 { - reg, _ := regexp.Compile(`_(\d+)\.ttx$`) - for k, _ := range self.m { - for _k, v := range m { - for _, _v := range v { - if _v == k { - self.m[k].file = reg.ReplaceAllString(_k, "") - self.m[k].ttx = _k - self.m[k].index = reg.FindStringSubmatch(_k)[1] - self.m[k].newName = randomStr(8) - break - } - } - } - } - } - ok := true - for _, v := range self.m { - if v.file == "" { - ok = false - log.Printf(`Missing the font: "%s".`, v.oldName) - } - } - return ok -} - -func (self *assProcessor) createFontSubset(font *fontInfo) bool { - ok := false - fn := fmt.Sprintf(`%s.txt`, font.file) - _, n, e, ne := splitPath(font.file) - if e == ".ttc" { - e = ".ttf" - } - if os.MkdirAll(self.output, os.ModePerm) != nil { - log.Println("Failed to create the output folder.") - return false - } - if os.WriteFile(fn, []byte(font.str), os.ModePerm) == nil { - _fn := fmt.Sprintf("%s.%s%s", ne, font.newName, e) - _fn = path.Join(self.output, _fn) - args := make([]string, 0) - args = append(args, "--text-file="+fn) - args = append(args, "--output-file="+_fn) - args = append(args, "--name-languages="+"*") - args = append(args, "--font-number="+font.index) - args = append(args, font.file) - if p, err := newProcess(nil, nil, nil, "", pyftsubset, args...); err == nil { - s, err := p.Wait() - ok = err == nil && s.ExitCode() == 0 - } - if !ok { - log.Printf(`Failed to subset font: "%s"[%s].`, n, font.index) - } else { - font.sFont = _fn - } - - } else { - log.Printf(`Failed to write the font text: "%s".`, n) - } - return ok -} - -func (self *assProcessor) createFontsSubset() bool { - err := os.RemoveAll(self.output) - if !(err == nil || err == os.ErrNotExist) { - log.Println("Failed to clean the output folder.") - return false - } - ok := 0 - l := len(self.m) - wg := new(sync.WaitGroup) - wg.Add(l) - m := new(sync.Mutex) - for _, item := range self.m { - go func(_item *fontInfo) { - _ok := self.createFontSubset(_item) - if _ok { - m.Lock() - ok++ - m.Unlock() - } - wg.Done() - }(item) - } - wg.Wait() - return ok == l -} - -func (self *assProcessor) changeFontName(font *fontInfo) bool { - ec := 0 - if self.dumpFont(font.sFont, true) { - fn := fmt.Sprintf("%s_0.ttx", font.sFont) - f, err := openFile(fn, true, false) - if err == nil { - defer func() { - _ = f.Close() - _ = os.Remove(fn) - }() - if xml, err := xmlquery.Parse(f); err == nil { - for _, v := range xml.SelectElements(`ttFont/name/namerecord`) { - id := v.SelectAttr("nameID") - switch id { - case "0": - v.FirstChild.Data = "Processed by " + LibFName + " at " + time.Now().Format("2006-01-02 15:04:05") - break - case "1", "3", "4", "6": - v.FirstChild.Data = font.newName - break - } - } - str := `<?xml version="1.0" encoding="UTF-8"?>` - str += xml.SelectElement("ttFont").OutputXML(true) - if os.WriteFile(fn, []byte(str), os.ModePerm) == nil { - args := make([]string, 0) - args = append(args, "-q") - args = append(args, "-f") - args = append(args, "-o", font.sFont) - args = append(args, fn) - ok := false - if p, err := newProcess(os.Stdin, nil, nil, "", ttx, args...); err == nil { - s, err := p.Wait() - ok = err == nil && s.ExitCode() == 0 - } - if !ok { - ec++ - _, n, _, _ := splitPath(font.sFont) - log.Printf(`Failed to compile the font: "%s".`, n) - } - } - } else { - log.Printf(`Faild to change the font name: "%s".`, font.oldName) - } - } - } - return ec == 0 -} - -func (self *assProcessor) changeFontsName() bool { - ok := 0 - l := len(self.m) - wg := new(sync.WaitGroup) - wg.Add(l) - m := new(sync.Mutex) - for _, item := range self.m { - go func(_item *fontInfo) { - _ok := self.changeFontName(_item) - if _ok { - m.Lock() - ok++ - m.Unlock() - } - wg.Done() - }(item) - } - wg.Wait() - return ok == l -} - -func (self *assProcessor) replaceFontNameInAss() bool { - ec := 0 - m := make(map[string]map[string]bool) - for _, v := range self.m { - for f, s := range self.subtitles { - if m[f] == nil { - m[f] = make(map[string]bool) - } - n := regexp.QuoteMeta(v.oldName) - reg, _ := regexp.Compile(fmt.Sprintf(`(Style:[^,\r\n]+,|\\fn)(@?)%s([,\\\}])`, n)) - if reg.MatchString(s) { - r := fmt.Sprintf("${1}${2}%s${3}", v.newName) - s = reg.ReplaceAllString(s, r) - m[f][v.oldName] = true - self.subtitles[f] = s - } - } - } - for f, s := range self.subtitles { - comments := make([]string, 0) - comments = append(comments, "[Script Info]") - comments = append(comments, "; ----- Font subset begin -----") - for k, _ := range m[f] { - comments = append(comments, fmt.Sprintf("; Font subset: %s - %s", self.m[k].newName, k)) - } - if len(comments) > 2 { - comments = append(comments, "") - comments = append(comments, "; Processed by "+LibFName+" at "+time.Now().Format("2006-01-02 15:04:05")) - comments = append(comments, "; ----- Font subset end -----") - comments = append(comments, "") - s = strings.Replace(s, "[Script Info]\r\n", strings.Join(comments, "\r\n"), 1) - _, n, _, _ := splitPath(f) - fn := path.Join(self.output, n) - ok := false - if os.WriteFile(fn, []byte(s), os.ModePerm) == nil { - ok = true - } else { - ec++ - } - if !ok { - log.Printf(`Failed to write the new ass file: "%s".`, fn) - } - } - } - return ec == 0 -} diff --git a/lib/go.mod b/lib/go.mod deleted file mode 100644 index 3be11ce..0000000 --- a/lib/go.mod +++ /dev/null @@ -1,17 +0,0 @@ -module mkvlib - -go 1.17 - -require ( - github.com/antchfx/xmlquery v1.3.8 - github.com/asticode/go-astisub v0.19.0 -) - -require ( - github.com/antchfx/xpath v1.2.0 // indirect - github.com/asticode/go-astikit v0.20.0 // indirect - github.com/asticode/go-astits v1.8.0 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect - golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect - golang.org/x/text v0.3.2 // indirect -) diff --git a/lib/mkv.go b/lib/mkv.go deleted file mode 100644 index e5eeb85..0000000 --- a/lib/mkv.go +++ /dev/null @@ -1,297 +0,0 @@ -package mkvlib - -import ( - "bytes" - "encoding/json" - "fmt" - "log" - "os" - "path" - "regexp" - "strings" -) - -const ( - mkvmerge = `mkvmerge` - mkvextract = `mkvextract` -) - -type mkvInfo struct { - Attachments []struct { - ID int `json:"id"` - FileName string `json:"file_name"` - Size int `json:"size"` - ContentType string `json:"content_type"` - } `json:"attachments"` - Tracks []struct { - ID int `json:"id"` - Type string `json:"type"` - Codec string `json:"codec"` - Properties struct { - Language string `json:"language"` - TrackName string `json:"track_name"` - } `json:"properties"` - } -} - -type mkvProcessor bool - -func (self *mkvProcessor) GetMKVInfo(file string) *mkvInfo { - buf := bytes.NewBufferString("") - if p, err := newProcess(nil, buf, nil, "", mkvmerge, "-J", file); err == nil { - if s, err := p.Wait(); err == nil && s.ExitCode() == 0 { - obj := new(mkvInfo) - _ = json.Unmarshal(buf.Bytes(), obj) - return obj - } - } - return nil -} - -func (self *mkvProcessor) DumpMKV(file, output string, subset bool) bool { - ec := 0 - obj := self.GetMKVInfo(file) - if obj == nil { - log.Printf(`Failed to get the mkv file info: "%s".`, file) - return false - } - attachments := make([]string, 0) - tracks := make([]string, 0) - for _, _item := range obj.Attachments { - attachments = append(attachments, fmt.Sprintf(`%d:%s`, _item.ID, path.Join(output, "fonts", _item.FileName))) - } - for _, _item := range obj.Tracks { - if _item.Type == "subtitles" { - s := fmt.Sprintf(`%d_%s_%s`, _item.ID, _item.Properties.Language, _item.Properties.TrackName) - if _item.Codec == "SubStationAlpha" { - s += ".ass" - } else { - s += ".sub" - } - tracks = append(tracks, fmt.Sprintf(`%d:%s`, _item.ID, path.Join(output, s))) - } - } - args := make([]string, 0) - args = append(args, file) - args = append(args, "attachments") - args = append(args, attachments...) - args = append(args, "tracks") - args = append(args, tracks...) - if p, err := newProcess(nil, nil, nil, "", mkvextract, args...); err == nil { - s, err := p.Wait() - ok := err == nil && s.ExitCode() == 0 - if ok { - if subset { - asses := make([]string, 0) - for _, _item := range tracks { - _arr := strings.Split(_item, ":") - f := _arr[len(_arr)-1] - if strings.HasSuffix(f, ".ass") { - asses = append(asses, f) - } - if len(asses) > 0 { - if !self.ASSFontSubset(asses, "", "", false) { - ec++ - } - } - } - } - } else { - ec++ - } - } else { - ec++ - } - return ec == 0 -} - -func (self *mkvProcessor) CheckSubset(file string) (bool, bool) { - obj := self.GetMKVInfo(file) - if obj == nil { - log.Printf(`Failed to get the mkv file info: "%s".`, file) - return false, true - } - ass := false - ok := false - reg, _ := regexp.Compile(`\.[A-Z0-9]{8}\.\S+$`) - for _, track := range obj.Tracks { - ass = track.Type == "subtitles" && track.Codec == "SubStationAlpha" - if ass { - break - } - } - for _, attachment := range obj.Attachments { - ok = !ass || (strings.HasPrefix(attachment.ContentType, "font/") && reg.MatchString(attachment.FileName)) - if ok { - break - } - } - return !ass || (ass && ok), false -} - -func (self *mkvProcessor) CreateMKV(file string, tracks, attachments []string, output, slang, stitle string, clean bool) bool { - args := make([]string, 0) - args = append(args, "--output", output) - if clean { - args = append(args, "--no-subtitles", "--no-attachments") - } - args = append(args, file) - for _, _item := range attachments { - args = append(args, "--attach-file", _item) - } - for _, _item := range tracks { - _, _, _, f := splitPath(_item) - _arr := strings.Split(f, "_") - _sl := slang - _st := stitle - if len(_arr) > 1 { - _sl = _arr[1] - } - if len(_arr) > 2 { - _st = _arr[2] - } - if _sl != "" { - args = append(args, "--language", "0:"+_sl) - } - if _st != "" { - args = append(args, "--track-name", "0:"+_st) - } - args = append(args, _item) - } - if p, err := newProcess(nil, nil, nil, "", mkvmerge, args...); err == nil { - s, err := p.Wait() - return err == nil && s.ExitCode() == 0 - } - return false -} - -func (self *mkvProcessor) DumpMKVs(dir, output string, subset bool) bool { - ec := 0 - files := findMKVs(dir) - l := len(files) - for i, item := range files { - p := strings.TrimPrefix(item, dir) - d, _, _, f := splitPath(p) - p = path.Join(output, d, f) - if !self.DumpMKV(item, p, subset) { - ec++ - log.Printf(`Failed to dump the mkv file "%s".`, item) - } - log.Printf("Dump (%d/%d) done.", i+1, l) - } - return ec == 0 -} - -func (self *mkvProcessor) QueryFolder(dir string) []string { - ec := 0 - lines := make([]string, 0) - files := findMKVs(dir) - l := len(files) - for i, file := range files { - a, b := self.CheckSubset(file) - if b { - ec++ - } else if !a { - lines = append(lines, file) - } - log.Printf("Query (%d/%d) done.", i+1, l) - } - return lines -} - -func (self *mkvProcessor) CreateMKVs(vDir, sDir, fDir, tDir, oDir string, slang, stitle string, clean bool) bool { - ec := 0 - if tDir == "" { - tDir = os.TempDir() - } - tDir = path.Join(tDir, randomStr(8)) - files, _ := findPath(vDir, fmt.Sprintf(`\.\S+$`)) - l := len(files) - for i, item := range files { - _, _, _, _f := splitPath(item) - tmp, _ := findPath(sDir, fmt.Sprintf(`%s\S*\.\S+$`, regexp.QuoteMeta(_f))) - asses := make([]string, 0) - subs := make([]string, 0) - p := path.Join(tDir, _f) - for _, sub := range tmp { - if strings.HasSuffix(sub, ".ass") { - _, _, _, __f := splitPath(sub) - _s := path.Join(p, __f) + ".ass" - _ = copyFileOrDir(sub, _s) - asses = append(asses, _s) - } else { - subs = append(subs, sub) - } - } - attachments := make([]string, 0) - tracks := make([]string, 0) - if len(asses) > 0 { - _ = os.RemoveAll(tDir) - if !self.ASSFontSubset(asses, fDir, "", false) { - ec++ - } else { - __p := path.Join(p, "subsetted") - attachments = findFonts(__p) - tracks, _ = findPath(__p, `\.ass$`) - } - } - tracks = append(tracks, subs...) - fn := path.Join(oDir, _f) + ".mkv" - if !self.CreateMKV(item, tracks, attachments, fn, slang, stitle, clean) { - ec++ - } - if ec > 0 { - log.Printf(`Failed to create the mkv file: "%s".`, item) - } - log.Printf("Create (%d/%d) done.", i+1, l) - } - _ = os.RemoveAll(tDir) - return ec == 0 -} - -func (self *mkvProcessor) MakeMKVs(dir, data, output, slang, sttlte string) bool { - ec := 0 - files := findMKVs(dir) - l := len(files) - for i, item := range files { - p := strings.TrimPrefix(item, dir) - d, n, _, f := splitPath(p) - p = path.Join(data, d, f) - _p := path.Join(p, "subsetted") - subs, _ := findPath(p, `\.sub`) - asses, _ := findPath(_p, `\.ass$`) - attachments := findFonts(_p) - tracks := append(subs, asses...) - fn := path.Join(output, d, n) - if !self.CreateMKV(item, tracks, attachments, fn, slang, sttlte, true) { - ec++ - log.Printf(`Faild to make the mkv file: "%s".`, item) - } - log.Printf("Make (%d/%d) done.", i+1, l) - } - return ec == 0 -} - -func (self *mkvProcessor) ASSFontSubset(files []string, fonts, output string, dirSafe bool) bool { - if len(files) == 0 { - return false - } - obj := new(assProcessor) - obj.files = files - obj._fonts = fonts - obj.output = output - d, _, _, _ := splitPath(obj.files[0]) - if obj._fonts == "" { - obj._fonts += path.Join(d, "fonts") - } - if obj.output == "" { - obj.output = d - dirSafe = true - } - if dirSafe { - obj.output = path.Join(obj.output, "subseted") - } - obj.fonts = findFonts(obj._fonts) - - return obj.parse() && obj.matchFonts() && obj.createFontsSubset() && obj.changeFontsName() && obj.replaceFontNameInAss() -} diff --git a/lib/shared.go b/lib/shared.go deleted file mode 100644 index b0cfb2f..0000000 --- a/lib/shared.go +++ /dev/null @@ -1,54 +0,0 @@ -package mkvlib - -import ( - "log" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" -) - -const libName = "mkvlib" -const libVer = "v1.0.2" - -const LibFName = libName + " " + libVer - -var _instance *mkvProcessor - -func GetInstance() *mkvProcessor { - ec := 0 - n := "PATH" - s := ":" - if runtime.GOOS == "windows" { - n = "path" - s = ";" - } - p := os.Getenv(n) - if !strings.HasSuffix(p, s) { - p += s - } - e, _ := os.Executable() - e, _ = filepath.Split(e) - p += e - _ = os.Setenv(n, p) - _, _ttx := exec.LookPath(ttx) - _, _pyftsubset := exec.LookPath(pyftsubset) - _, _mkvextract := exec.LookPath(mkvextract) - _, _mkvmerge := exec.LookPath(mkvmerge) - if _ttx != nil || _pyftsubset != nil { - log.Printf(`Missing dependency: fonttools (need "%s" & "%s").`, ttx, pyftsubset) - ec++ - } - if _mkvextract != nil || _mkvmerge != nil { - log.Printf(`Missing dependency: mkvtoolnix (need "%s" & "%s").`, mkvextract, mkvmerge) - ec++ - } - if ec > 0 { - return nil - } - if _instance == nil { - _instance = new(mkvProcessor) - } - return _instance -} diff --git a/lib/utils.go b/lib/utils.go deleted file mode 100644 index a76a05d..0000000 --- a/lib/utils.go +++ /dev/null @@ -1,220 +0,0 @@ -package mkvlib - -import ( - "errors" - "fmt" - "io" - "math/rand" - "os" - "os/exec" - "path" - "path/filepath" - "regexp" - "strings" - "time" -) - -func newProcess(stdin io.Reader, stdout, stderr io.Writer, dir, prog string, args ...string) (p *os.Process, err error) { - cmd := exec.Command(prog, args...) - if dir != "" { - cmd.Dir = dir - } - if stdin != nil { - cmd.Stdin = stdin - } - if stdout != nil { - cmd.Stdout = stdout - } - if stderr != nil { - cmd.Stderr = stderr - } - err = cmd.Start() - if err == nil { - p = cmd.Process - } - return -} - -func newDir(path string) error { - return os.MkdirAll(path, os.ModePerm) -} - -func queryPath(path string, cb func(string) bool) error { - return filepath.Walk(path, func(path string, f os.FileInfo, err error) error { - if f == nil { - return err - } - if f.IsDir() { - return nil - } - if cb(path) { - return nil - } - return errors.New("call cb return false") - }) -} - -func findPath(path, expr string) (list []string, err error) { - list = make([]string, 0) - reg, e := regexp.Compile(expr) - if e != nil { - err = e - return - } - err = queryPath(path, func(path string) bool { - if expr == "" || reg.MatchString(path) { - list = append(list, path) - } - return true - }) - return -} - -func copyFolder(src, dst string) error { - e, f := isExists(src) - if !e { - return errors.New("src is not exists") - } - if !f { - return errors.New("src is not folder") - } - if newDir(dst) != nil { - return errors.New("faild to create dst folder") - } - s := len(src) - if _, n, _, _ := splitPath(dst); n == "" { - _, n, _, _ = splitPath(src) - if n == "" { - _, n, _, _ = splitPath(src[:len(src)-1]) - } - dst = fmt.Sprintf("%s/%s", dst, n) - } - return filepath.Walk(src, func(path string, f os.FileInfo, err error) error { - if f == nil { - return err - } - if f.IsDir() { - return nil - } - return copyFile(path, dst+"/"+path[s:]) - }) -} - -func newFile(fp string) (file *os.File, err error) { - dir, _ := filepath.Split(fp) - if dir != "" { - err = newDir(dir) - if err != nil { - return - } - } - if err == nil { - file, err = os.Create(fp) - } - return -} - -func openFile(filepath string, readOnly, create bool) (file *os.File, err error) { - f := os.O_RDWR | os.O_CREATE - if readOnly { - f = os.O_RDONLY - } - file, err = os.OpenFile(filepath, f, os.ModePerm) - if err != nil && create { - file, err = newFile(filepath) - } - return -} - -func copyFile(src, dst string) error { - e, f := isExists(src) - if !e { - return errors.New("src is not exists") - } - if f { - return errors.New("src is not file") - } - if _, n, _, _ := splitPath(dst); n == "" { - _, n, _, _ = splitPath(src) - dst = path.Join(dst, n) - } - sf, err := openFile(src, true, false) - if err != nil { - return err - } - defer sf.Close() - df, err := openFile(dst, false, true) - if err != nil { - return err - } - defer df.Close() - - _, err = io.Copy(df, sf) - return err -} - -func splitPath(p string) (dir, name, ext, namewithoutext string) { - dir, name = filepath.Split(p) - ext = filepath.Ext(name) - n := strings.LastIndex(name, ".") - if n > 0 { - namewithoutext = name[:n] - } - return -} - -func isExists(path string) (exists bool, isFolder bool) { - f, err := os.Stat(path) - exists = err == nil || os.IsExist(err) - if exists { - isFolder = f.IsDir() - } - return -} - -func copyFileOrDir(src, dst string) error { - e, f := isExists(src) - if !e { - return errors.New("src is not exists") - } - if !f { - return copyFile(src, dst) - } - return copyFolder(src, dst) -} - -func randomStr(l int) string { - str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - bytes := []byte(str) - var result []byte - lstr := len(str) - 1 - for i := 0; i < l; i++ { - n := randomNumber(0, lstr) - result = append(result, bytes[n]) - } - return string(result) -} - -var r = rand.New(rand.NewSource(time.Now().UnixNano())) - -func randomN(n int) int { - return r.Intn(n) -} - -func randomNumber(min, max int) int { - sub := max - min + 1 - if sub <= 1 { - return min - } - return min + randomN(sub) -} - -func findMKVs(dir string) []string { - list, _ := findPath(dir, `\.mkv$`) - return list -} - -func findFonts(dir string) []string { - list, _ := findPath(dir, `\.((ttf)|(otf)|(ttc)|(fon))$`) - return list -} |
