diff --git a/engine/config.go b/engine/config.go index bcce71c7c..84c9c606e 100644 --- a/engine/config.go +++ b/engine/config.go @@ -24,9 +24,12 @@ const ( const ( defaultTrackerListURL = "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt" defaultScraperURL = "https://raw.githubusercontent.com/boypt/simple-torrent/master/scraper-config.json" + fileSuffix = "avi|wmv|mpeg|mp4|m4v|mov|asf|flv|f4v|rmvb|rm|3gp|vob|jpe?g|png|gif|mp3|m4a" ) type Config struct { + NoDefaultPortForwarding bool + DisableUTP bool AutoStart bool EngineDebug bool MuteEngineLog bool @@ -34,8 +37,6 @@ type Config struct { ObfsRequirePreferred bool DisableTrackers bool DisableIPv6 bool - NoDefaultPortForwarding bool - DisableUTP bool DownloadDirectory string WatchDirectory string EnableUpload bool @@ -50,6 +51,7 @@ type Config struct { ProxyURL string RssURL string ScraperURL string + FileSuffix string } func InitConf(specPath string) (*Config, error) { @@ -74,6 +76,7 @@ func InitConf(specPath string) (*Config, error) { viper.SetDefault("IncomingPort", 50007) viper.SetDefault("TrackerListURL", defaultTrackerListURL) viper.SetDefault("ScraperURL", defaultScraperURL) + viper.SetDefault("FileSuffix", fileSuffix) // user specific config path if stat, err := os.Stat(specPath); stat != nil && err == nil { diff --git a/engine/engine.go b/engine/engine.go index b7c64e01b..fe8ac1221 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -2,7 +2,11 @@ package engine import ( "bufio" + "cloud-torrent/engine/ffmpeg" "fmt" + eglog "github.com/anacrolix/log" + "github.com/anacrolix/torrent" + "github.com/anacrolix/torrent/metainfo" "io" "log" "net/http" @@ -10,13 +14,10 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strings" "sync" "time" - - eglog "github.com/anacrolix/log" - "github.com/anacrolix/torrent" - "github.com/anacrolix/torrent/metainfo" ) const ( @@ -270,6 +271,11 @@ func genEnv(dir, path, hash, ttype, api string, size int64, ts int64) []string { return env } +func (e *Engine) Tomp4(input, output string) error { + ffmpeg.Tomp4(input, output) + return nil +} + func (e *Engine) upsertTorrent(tt *torrent.Torrent) *Torrent { ih := tt.InfoHash().HexString() e.RLock() @@ -313,7 +319,7 @@ func (e *Engine) StartTorrent(infohash string) error { t.Started = true t.StartedAt = time.Now() for _, f := range t.Files { - if f != nil { + if regexp.MustCompile(e.config.FileSuffix).MatchString(strings.ToLower(f.Path)) { f.Started = true } } @@ -323,8 +329,17 @@ func (e *Engine) StartTorrent(infohash string) error { // start all files by setting the priority to normal for _, f := range t.t.Files() { - f.SetPriority(torrent.PiecePriorityNormal) + log.Println(f.Path()) + log.Println(regexp.MustCompile(e.config.FileSuffix).MatchString(strings.ToLower(f.Path()))) + if regexp.MustCompile(e.config.FileSuffix).MatchString(strings.ToLower(f.Path())) { + f.SetPriority(torrent.PiecePriorityNormal) + } else { + f.SetPriority(torrent.PiecePriorityNone) + } } + + // call to DownloadAll cause StartFile/StopFile not working + // t.t.DownloadAll() } return nil } diff --git a/engine/ffmpeg/ffmpeg.go b/engine/ffmpeg/ffmpeg.go new file mode 100644 index 000000000..9f6d012bc --- /dev/null +++ b/engine/ffmpeg/ffmpeg.go @@ -0,0 +1,69 @@ +//go:build !windows +// +build !windows + +package ffmpeg + +import ( + "fmt" + "github.com/xfrr/goffmpeg/transcoder" + "log" + "path" + "sync" +) + +var mm = make(map[string]float64) + +var mutex sync.RWMutex + +func Tomp4(inputPath, outputPath string) { + log.Println("input-output:", inputPath, outputPath) + outputPath = outputPath + ".mp4" + mutex.RLock() + key := path.Base(outputPath) + defer mutex.RUnlock() + if t := mm[key]; t != 0 { + log.Println("is doing ", inputPath) + return + } + + trans := new(transcoder.Transcoder) + + //fpath := ffmpeg.Configuration{FfprobeBin: "E:/worktool/ffmpeg/bin/ffprobe.exe ", FfmpegBin: "E:/worktool/ffmpeg/bin/ffmpeg.exe "} + //trans.SetConfiguration(fpath) + err := trans.Initialize(inputPath, outputPath) + log.Println("err:", err) + //trans.MediaFile().SetResolution("320x240") + //trans.MediaFile().SetVideoCodec("xvid") + trans.MediaFile().SetResolution("320x240") + trans.MediaFile().SetVideoBitRate("400k") + trans.MediaFile().SetFrameRate(25) + + go func() { + done := trans.Run(true) + fmt.Print(done) + progress := trans.Output() + for msg := range progress { + mm[key] = msg.Progress + fmt.Println(msg) + } + delete(mm, key) + }() + +} + +func ListProgress(key string) float64 { + //res := make(map[string]float64) + //for transs := range mm { + // out := mm[transs] + // num := <-out + // filenameWithSuffix := path.Base(transs) + ".mp4" + // fmt.Println("get file", filenameWithSuffix) + // res[filenameWithSuffix] = num.Progress + //} + //return res + if out := mm[key]; out != 0 { + return out + } + return 0 + +} diff --git a/engine/ffmpeg/ffmpeg_win.go b/engine/ffmpeg/ffmpeg_win.go new file mode 100644 index 000000000..00b2d3f80 --- /dev/null +++ b/engine/ffmpeg/ffmpeg_win.go @@ -0,0 +1,70 @@ +//go:build windows +// +build windows + +package ffmpeg + +import ( + "fmt" + "github.com/xfrr/goffmpeg/ffmpeg" + "github.com/xfrr/goffmpeg/transcoder" + "log" + "path" + "sync" +) + +var mm = make(map[string]float64) + +var mutex sync.RWMutex + +func Tomp4(inputPath, outputPath string) { + log.Println("input-output:", inputPath, outputPath) + outputPath = outputPath + ".mp4" + mutex.RLock() + key := path.Base(outputPath) + defer mutex.RUnlock() + if t := mm[key]; t != 0 { + log.Println("is doing ", inputPath) + return + } + + trans := new(transcoder.Transcoder) + + fpath := ffmpeg.Configuration{FfprobeBin: "E:/worktool/ffmpeg/bin/ffprobe.exe ", FfmpegBin: "E:/worktool/ffmpeg/bin/ffmpeg.exe "} + trans.SetConfiguration(fpath) + err := trans.Initialize(inputPath, outputPath) + log.Println("err:", err) + //trans.MediaFile().SetResolution("320x240") + //trans.MediaFile().SetVideoCodec("xvid") + trans.MediaFile().SetResolution("320x240") + trans.MediaFile().SetVideoBitRate("400k") + trans.MediaFile().SetFrameRate(25) + + go func() { + done := trans.Run(true) + fmt.Print(done) + progress := trans.Output() + for msg := range progress { + mm[key] = msg.Progress + fmt.Println(msg) + } + delete(mm, key) + }() + +} + +func ListProgress(key string) float64 { + //res := make(map[string]float64) + //for transs := range mm { + // out := mm[transs] + // num := <-out + // filenameWithSuffix := path.Base(transs) + ".mp4" + // fmt.Println("get file", filenameWithSuffix) + // res[filenameWithSuffix] = num.Progress + //} + //return res + if out := mm[key]; out != 0 { + return out + } + return 0 + +} diff --git a/go.mod b/go.mod index e35f6ba05..56f0a69d7 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect github.com/valyala/fasthttp v1.23.0 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect + github.com/xfrr/goffmpeg v0.0.0-20200825100927-5550d238df5c github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect github.com/yudai/gojsondiff v1.0.0 // indirect github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect diff --git a/go.sum b/go.sum index 1f6b397bc..04458dc63 100644 --- a/go.sum +++ b/go.sum @@ -975,6 +975,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xfrr/goffmpeg v0.0.0-20200825100927-5550d238df5c h1:ydcAlElffxxmOn982VmNsx56UM2Op2OetAPura00Bec= +github.com/xfrr/goffmpeg v0.0.0-20200825100927-5550d238df5c/go.mod h1:fVs4qpwtgjOHD31cTmdHppcr/6vD8QHrAVAu2jTSVFI= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= diff --git a/main.go b/main.go index 319f19ae5..e0a685089 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,7 @@ var VERSION = "0.0.0-src" //set with ldflags func main() { s := server.Server{ - Title: "SimpleTorrent", + Title: "开始", Port: 3000, } diff --git a/server/server.go b/server/server.go index 1ad9a128f..12321040b 100644 --- a/server/server.go +++ b/server/server.go @@ -71,9 +71,11 @@ type Server struct { //torrent engine engine *engine.Engine - state struct { + + state struct { velox.State sync.Mutex + ffm []*ffm Config engine.Config SearchProviders scraper.Config Downloads *fsNode diff --git a/server/server_api.go b/server/server_api.go index 529b03725..c61554afa 100644 --- a/server/server_api.go +++ b/server/server_api.go @@ -87,6 +87,10 @@ func (s *Server) apiGET(w http.ResponseWriter, r *http.Request) error { case "enginedebug": w.Header().Set("Content-Type", "text/plain") s.engine.WriteStauts(w) + case "tomp4": + path := s.engine.Config().DownloadDirectory + "/" + s.engine.Tomp4(path+r.URL.Query().Get("input"), path+r.URL.Query().Get("output")) + s.engine.WriteStauts(w) default: return errUnknowAct } diff --git a/server/server_files.go b/server/server_files.go index 16376e12c..11a40c04a 100644 --- a/server/server_files.go +++ b/server/server_files.go @@ -1,6 +1,7 @@ package server import ( + "cloud-torrent/engine/ffmpeg" "errors" "fmt" "io/ioutil" @@ -14,15 +15,21 @@ import ( "github.com/jpillora/archive" ) -const fileNumberLimit = 1000 +const fileNumberLimit = 100000 type fsNode struct { Name string Size int64 Modified time.Time + Process float64 Children []*fsNode } +type ffm struct { + File string + Size float64 +} + func (s *Server) listFiles() *fsNode { rootDir := s.state.Config.DownloadDirectory root := &fsNode{} @@ -84,6 +91,8 @@ func list(path string, info os.FileInfo, node *fsNode, n *int) error { if (*n) > fileNumberLimit { return errors.New("Over file limit") //limit number of files walked } + m := ffmpeg.ListProgress(info.Name()) + node.Process = m node.Name = info.Name() node.Size = info.Size() node.Modified = info.ModTime() diff --git a/server/server_http.go b/server/server_http.go index 229c51705..3cdf2d3b9 100644 --- a/server/server_http.go +++ b/server/server_http.go @@ -9,7 +9,7 @@ import ( ) func (s *Server) webHandle(w http.ResponseWriter, r *http.Request) { - //handle realtime client library + // serve realtime client library if r.URL.Path == "/js/velox.js" { velox.JS.ServeHTTP(w, r) return @@ -18,32 +18,42 @@ func (s *Server) webHandle(w http.ResponseWriter, r *http.Request) { s.rssh.ServeHTTP(w, r) return } - //handle realtime client connections + // serve realtime client connection if r.URL.Path == "/sync" { conn, err := velox.Sync(&s.state, w, r) if err != nil { log.Printf("sync failed: %s", err) return } + + // use mutex to protect access to state.Users + s.state.Lock() s.state.Users[conn.ID()] = r.RemoteAddr s.state.Push() + s.state.Unlock() + conn.Wait() + + // use mutex to protect access to state.Users + s.state.Lock() delete(s.state.Users, conn.ID()) s.state.Push() + s.state.Unlock() + return } - //search + // search if strings.HasPrefix(r.URL.Path, "/search") { s.scraperh.ServeHTTP(w, r) return } - //api call + // API calls if strings.HasPrefix(r.URL.Path, "/api/") { w.Header().Set("Access-Control-Allow-Headers", "authorization") s.restAPIhandle(w, r) return } - //no match, assume static file + // no matching path, assume static file s.files.ServeHTTP(w, r) } diff --git a/static/files/js/config-controller.js b/static/files/js/config-controller.js index b7b8c239f..e03f6026b 100644 --- a/static/files/js/config-controller.js +++ b/static/files/js/config-controller.js @@ -20,7 +20,8 @@ app.controller("ConfigController", function ($scope, $rootScope, storage, api) { "ProxyURL", "TrackerListURL", "AlwaysAddTrackers", - "RssURL" + "RssURL", + "FileSuffix" ]; $scope.configTip = { diff --git a/static/files/js/downloads-controller.js b/static/files/js/downloads-controller.js index 3d0d637f0..9c72e1133 100644 --- a/static/files/js/downloads-controller.js +++ b/static/files/js/downloads-controller.js @@ -34,9 +34,9 @@ app.controller("NodeController", function($scope, $rootScope, $http, $timeout) { } var path = (n.$path = pathArray.join("/")); n.$closed = $scope.agoHrs(n.Modified) > 24; - $scope.audioPreview = /\.(mp3|m4a)$/.test(path); - $scope.imagePreview = /\.(jpe?g|png|gif)$/.test(path); - $scope.videoPreview = /\.(mp4|mkv|mov)$/.test(path); + $scope.audioPreview = /\.(mp3|m4a)$/i.test(path); + $scope.imagePreview = /\.(jpe?g|png|gif)$/i.test(path); + $scope.videoPreview = /\.(avi|wmv|mpeg|mp4|m4v|mov|asf|flv|f4v|rmvb|rm|3gp|vob)$/i.test(path); //search for this file var torrents = $rootScope.state.Torrents; @@ -109,4 +109,15 @@ app.controller("NodeController", function($scope, $rootScope, $http, $timeout) { $scope.togglePreview = function() { $scope.showPreview = !$scope.showPreview; }; + $scope.tomp4 = function() { + $http.get("api/tomp4?input=" + n.$path+"&output="+n.$path); + }; + $scope.toaria = function() { + console.log() + $http.post("https://raspberrypi:6800/jsonrpc", '{"jsonrpc": "2.0", "method": "aria2.addUri","id": "QXJpYU5nXzE2MzgwMjA0NDFfMC42MzAwMTQ5MDIyNTY4NzY2","params": [["https://oloking.xyz/download/'+n.$path+'"],{}]}', + { + transformRequest: [] + }) + }; + }); diff --git a/static/files/template/download-tree.html b/static/files/template/download-tree.html index e3c026e55..ad68b8682 100644 --- a/static/files/template/download-tree.html +++ b/static/files/template/download-tree.html @@ -9,16 +9,18 @@