diff --git a/README.md b/README.md index 9cce8aa7..a82e6459 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,19 @@ Image of the frontend UI - Automatic stop after seeding ratio reached - Pushbullet notification on torrent complete - Automatic move of completed torrent to new directory (leave symlink behind for seeding) - - Doesn't work on Windows yet, have to copy file for now + - Symlinks don't work on Windows yet, have to copy file for now ## Roadmap - Early-Mid 2018 + - [X] Ability to modify storage path of torrent after it has been added + + - [X] Backend to frontend notification messages + + - [X] Global Rate Limiting for Upload/Download Speed + + - [X] Add torrents from watch folder (cron job every 5 minutes) + - [ ] Unit testing completed for a large portion of the package - [ ] Stability/bug fixing/Optimization rewrite of some of the core structures of the WebUI and base server @@ -40,8 +48,8 @@ Image of the frontend UI - [ ] Ability to set priority for individual files (just added to anacrolix/torrent so coming soon, already added to my UI) - [ ] Ability to view TOML settings from WebUI (and perhaps change a few as well) - - - [ ] Ability to modify storage path of torrent after it has been added + + - [ ] Authentication from client to server - Late 2018 @@ -96,6 +104,12 @@ The `config.toml` file contains all of the settings for the server part of the a SeedRatioStop = 1.50 #automatically stops the torrent after it reaches this seeding ratio #Relative or absolute path accepted, the server will convert any relative path to an absolute path. DefaultMoveFolder = 'downloaded' #default path that a finished torrent is symlinked to after completion. Torrents added via RSS will default here + TorrentWatchFolder = 'torrentUpload' #folder path that is watched for .torrent files and adds them automatically every 5 minutes + + #Limits your upload and download speed globally, all are averages and not burst protected (usually burst on start). + #Low = ~.05MB/s, Medium = ~.5MB/s, High = ~1.5MB/s + UploadRateLimit = "Unlimited" #Options are "Low", "Medium", "High", "Unlimited" #Unlimited is default + DownloadRateLimit = "Unlimited" [notifications] diff --git a/config.toml b/config.toml index c736fc36..72bcdb96 100644 --- a/config.toml +++ b/config.toml @@ -3,7 +3,7 @@ ServerPort = ":8000" #leave format as is it expects a string with colon ServerAddr = "" #blank will bind to default IP address, usually fine to leave be - LogLevel = "Info" # Options = Debug, Info, Warn, Error, Fatal, Panic + LogLevel = "Warn" # Options = Debug, Info, Warn, Error, Fatal, Panic LogOutput = "file" #Options = file, stdout #file will print it to logs/server.log SeedRatioStop = 1.50 #automatically stops the torrent after it reaches this seeding ratio @@ -19,7 +19,7 @@ [notifications] - PushBulletToken = "o.QW6G7F6FUOKXCUKmw948fBceCUn0msFi" #add your pushbullet api token here to notify of torrent completion to pushbullet + PushBulletToken = "" #add your pushbullet api token here to notify of torrent completion to pushbullet [EncryptionPolicy] diff --git a/documentation/images/frontend.png b/documentation/images/frontend.png index d56087e2..901adf9a 100644 Binary files a/documentation/images/frontend.png and b/documentation/images/frontend.png differ diff --git a/engine/cronJobs.go b/engine/cronJobs.go index 291f0a54..80752a42 100644 --- a/engine/cronJobs.go +++ b/engine/cronJobs.go @@ -2,6 +2,7 @@ package engine import ( "io/ioutil" + "os" "path/filepath" "github.com/anacrolix/torrent" @@ -46,9 +47,9 @@ func CheckTorrentWatchFolder(c *cron.Cron, db *storm.DB, tclient *torrent.Client continue } - //os.Remove(fullFilePathAbs) //delete the torrent after adding it and copying it over + os.Remove(fullFilePathAbs) //delete the torrent after adding it and copying it over Logger.WithFields(logrus.Fields{"Source Folder": fullFilePathAbs, "Destination Folder": fullNewFilePathAbs, "Torrent": file.Name()}).Info("Added torrent from watch folder, and moved torrent file") - StartTorrent(clientTorrent, torrentLocalStorage, db, config.TorrentConfig.DataDir, "file", file.Name(), config.DefaultMoveFolder, "default", config.TFileUploadFolder) + StartTorrent(clientTorrent, torrentLocalStorage, db, "file", fullNewFilePathAbs, config.DefaultMoveFolder, "default", config) } } @@ -84,7 +85,7 @@ func RefreshRSSCron(c *cron.Cron, db *storm.DB, tclient *torrent.Client, torrent Logger.WithFields(logrus.Fields{"err": err, "Torrent": RSSTorrent.Title}).Warn("Unable to add torrent to torrent client!") break //break out of the loop entirely for this message since we hit an error } - StartTorrent(clientTorrent, torrentLocalStorage, db, config.TorrentConfig.DataDir, "magnet", "", config.DefaultMoveFolder, "RSS", config.TFileUploadFolder) //TODO let user specify torrent default storage location and let change on fly + StartTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", config.DefaultMoveFolder, "RSS", config) //TODO let user specify torrent default storage location and let change on fly singleFeed.Torrents = append(singleFeed.Torrents, singleRSSTorrent) } diff --git a/engine/doneTorrentActions.go b/engine/doneTorrentActions.go index 05dfbcb2..167a8b76 100644 --- a/engine/doneTorrentActions.go +++ b/engine/doneTorrentActions.go @@ -1,8 +1,6 @@ package engine import ( - "fmt" - "io" "os" "path/filepath" "runtime" @@ -20,22 +18,21 @@ func MoveAndLeaveSymlink(config FullClientSettings, tHash string, db *storm.DB, tStorage := Storage.FetchTorrentFromStorage(db, tHash) Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName}).Info("Move and Create symlink started for torrent") var oldFilePath string - if moveDone { + if moveDone { //only occurs on manual move oldFilePathTemp := filepath.Join(oldPath, tStorage.TorrentName) - oldFilePath, err := filepath.Abs(oldFilePathTemp) + var err error + oldFilePath, err = filepath.Abs(oldFilePathTemp) if err != nil { Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": oldFilePath}).Error("Cannot create absolute file path!") } - - fmt.Println("oldfilepath", oldFilePath) } else { oldFilePathTemp := filepath.Join(config.TorrentConfig.DataDir, tStorage.TorrentName) - oldFilePath, err := filepath.Abs(oldFilePathTemp) + var err error + oldFilePath, err = filepath.Abs(oldFilePathTemp) if err != nil { Logger.WithFields(logrus.Fields{"Torrent Name": tStorage.TorrentName, "Filepath": oldFilePath}).Error("Cannot create absolute file path!") } } - newFilePathTemp := filepath.Join(tStorage.StoragePath, tStorage.TorrentName) newFilePath, err := filepath.Abs(newFilePathTemp) if err != nil { @@ -55,70 +52,27 @@ func MoveAndLeaveSymlink(config FullClientSettings, tHash string, db *storm.DB, } if oldFilePath != newFilePath { - if runtime.GOOS == "windows" { //TODO the windows symlink is broken on windows 10 creator edition, so doing a copy for now until Go 1.11 - if oldFileInfo.IsDir() { - os.Mkdir(newFilePath, 0755) - if moveDone { - err := folderCopy.Copy(config.TorrentConfig.DataDir, newFilePath) - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": config.TorrentConfig.DataDir, "New File Path": newFilePath, "error": err}).Error("Error Copying Folder!") - } - } else { - err := folderCopy.Copy(oldFilePath, newFilePath) //copy the folder to the new location - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error Copying Folder!") - } - - } - os.Chmod(newFilePath, 0777) - notifyUser(tStorage, config, db) - return - } - srcFile, err := os.Open(oldFilePath) - defer srcFile.Close() - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "error": err}).Error("Windows: Cannot open old file for copy") - return - } - destFile, err := os.Create(newFilePath) - defer destFile.Close() - if err != nil { - Logger.WithFields(logrus.Fields{"New File Path": newFilePath, "error": err}).Error("Windows: Cannot open new file for copying into") - return - } - - bytesWritten, err := io.Copy(destFile, srcFile) - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Windows: Cannot copy old file into new") - return - } - err = destFile.Sync() - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Windows: Error syncing new file to disk") - } - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "bytesWritten": bytesWritten}).Info("Windows Torrent Copy Completed") - notifyUser(tStorage, config, db) - } else { - - folderCopy.Copy(oldFilePath, newFilePath) - os.Chmod(newFilePath, 0777) //changing permissions on the new file to be permissive - os.RemoveAll(oldFilePath) - if moveDone { - err := os.Symlink(newFilePath, config.TorrentConfig.DataDir) - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": config.TorrentConfig.DataDir, "New File Path": newFilePath, "error": err}).Error("Error creating symlink") - return - } - } else { - err := os.Symlink(newFilePath, oldFilePath) //For all other OS's create a symlink - if err != nil { - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error creating symlink") - return - } - } - notifyUser(tStorage, config, db) - Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath}).Info("Moving completed torrent") + newFilePathDir := filepath.Dir(newFilePath) + os.Mkdir(newFilePathDir, 0755) + err := folderCopy.Copy(oldFilePath, newFilePath) //copy the folder to the new location + if err != nil { + Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error Copying Folder!") } + os.Chmod(newFilePath, 0777) + if runtime.GOOS != "windows" { //TODO the windows symlink is broken on windows 10 creator edition, so on the other platforms create symlink (windows will copy) until Go1.11 + os.RemoveAll(oldFilePath) + err = os.Symlink(newFilePath, oldFilePath) + if err != nil { + Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath, "error": err}).Error("Error creating symlink") + } + } + if moveDone == false { + tStorage.TorrentMoved = true //TODO error handling instead of just saying torrent was moved when it was not + notifyUser(tStorage, config, db) //Only notify if we haven't moved yet, don't want to push notify user every time user uses change storage button + } + Logger.WithFields(logrus.Fields{"Old File Path": oldFilePath, "New File Path": newFilePath}).Info("Moving completed torrent") + tStorage.StoragePath = filepath.Dir(newFilePath) + Storage.UpdateStorageTick(db, tStorage) } } diff --git a/engine/engine.go b/engine/engine.go index de3cb96c..15515fc9 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -4,7 +4,6 @@ import ( "fmt" "io/ioutil" "os" - "path/filepath" "strconv" "strings" "time" @@ -128,7 +127,7 @@ func readTorrentFileFromDB(element *Storage.TorrentLocal, tclient *torrent.Clien } //StartTorrent creates the storage.db entry and starts A NEW TORRENT and adds to the running torrent array -func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.TorrentLocal, torrentDbStorage *storm.DB, dataDir, torrentType, torrentFileName, torrentStoragePath, labelValue, tFileUploadFolder string) { +func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.TorrentLocal, torrentDbStorage *storm.DB, torrentType, torrentFilePathAbs, torrentStoragePath, labelValue string, config FullClientSettings) { timedOut := timeOutInfo(clientTorrent, 45) //seeing if adding the torrent times out (giving 45 seconds) if timedOut { //if we fail to add the torrent return return @@ -147,6 +146,7 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.To torrentLocalStorage.Label = labelValue torrentLocalStorage.DateAdded = time.Now().Format("Jan _2 2006") torrentLocalStorage.StoragePath = torrentStoragePath + torrentLocalStorage.TempStoragePath = config.TorrentConfig.DataDir torrentLocalStorage.TorrentName = clientTorrent.Name() torrentLocalStorage.TorrentUploadLimit = true //by default all of the torrents will stop uploading after the global rate is set. torrentLocalStorage.TorrentMoved = false //by default the torrent has no been moved. @@ -154,8 +154,6 @@ func StartTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage Storage.To torrentLocalStorage.TorrentType = torrentType //either "file" or "magnet" maybe more in the future torrentLocalStorage.TorrentSize = clientTorrent.Length() //Length will change as we cancel files so store it in DB if torrentType == "file" { //if it is a file read the entire file into the database for us to spit out later - torrentFilePath := filepath.Join(tFileUploadFolder, torrentFileName) - torrentFilePathAbs, err := filepath.Abs(torrentFilePath) torrentfile, err := ioutil.ReadFile(torrentFilePathAbs) torrentLocalStorage.TorrentFileName = torrentFilePathAbs if err != nil { @@ -236,11 +234,10 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto PercentDone := fmt.Sprintf("%.2f", float32(singleTorrent.BytesCompleted())/float32(singleTorrentFromStorage.TorrentSize)) fullClientDB.TorrentHash = TempHash fullClientDB.PercentDone = PercentDone - fullClientDB.DataBytesRead = fullStruct.ConnStats.DataBytesRead //used for calculations not passed to client calculating up/down speed - fullClientDB.DataBytesWritten = fullStruct.ConnStats.DataBytesWritten //used for calculations not passed to client calculating up/down speed + fullClientDB.DataBytesRead = fullStruct.ConnStats.BytesReadData //used for calculations not passed to client calculating up/down speed + fullClientDB.DataBytesWritten = fullStruct.ConnStats.BytesWrittenData //used for calculations not passed to client calculating up/down speed fullClientDB.ActivePeers = activePeersString + " / (" + totalPeersString + ")" fullClientDB.TorrentHashString = TempHash.String() - fullClientDB.StoragePath = singleTorrentFromStorage.StoragePath fullClientDB.TorrentName = singleTorrentFromStorage.TorrentName fullClientDB.DateAdded = singleTorrentFromStorage.DateAdded fullClientDB.TorrentLabel = singleTorrentFromStorage.Label @@ -252,7 +249,7 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto TempHash := singleTorrent.InfoHash() if previousElement.TorrentHashString == TempHash.String() { //matching previous to new CalculateTorrentSpeed(singleTorrent, fullClientDB, previousElement) - fullClientDB.TotalUploadedBytes = singleTorrentFromStorage.UploadedBytes + (fullStruct.ConnStats.DataBytesWritten - previousElement.DataBytesWritten) + fullClientDB.TotalUploadedBytes = singleTorrentFromStorage.UploadedBytes + (fullStruct.ConnStats.BytesWrittenData - previousElement.DataBytesWritten) } } } @@ -276,7 +273,7 @@ func CreateRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Sto } //CreateFileListArray creates a file list for a single torrent that is selected and sent to the server -func CreateFileListArray(tclient *torrent.Client, selectedHash string, db *storm.DB) TorrentFileList { +func CreateFileListArray(tclient *torrent.Client, selectedHash string, db *storm.DB, config FullClientSettings) TorrentFileList { runningTorrents := tclient.Torrents() //don't need running torrent array since we aren't adding or deleting from storage torrentFileListStorage := Storage.FetchTorrentFromStorage(db, selectedHash) TorrentFileListSelected := TorrentFileList{} @@ -289,11 +286,7 @@ func CreateFileListArray(tclient *torrent.Client, selectedHash string, db *storm for _, singleFile := range torrentFilesRaw { TorrentFileStruct.TorrentHashString = tempHash TorrentFileStruct.FileName = singleFile.DisplayPath() - absFilePath, err := filepath.Abs(singleFile.Path()) - if err != nil { - Logger.WithFields(logrus.Fields{"file": singleFile.Path()}).Debug("Unable to create absolute path") - } - TorrentFileStruct.FilePath = absFilePath + TorrentFileStruct.FilePath = singleFile.Path() PieceState := singleFile.State() var downloadedBytes int64 for _, piece := range PieceState { diff --git a/engine/engineHelpers.go b/engine/engineHelpers.go index 08036f62..84c3c137 100644 --- a/engine/engineHelpers.go +++ b/engine/engineHelpers.go @@ -62,7 +62,7 @@ func CopyFile(srcFile string, destFile string) { func CalculateTorrentSpeed(t *torrent.Torrent, c *ClientDB, oc ClientDB) { now := time.Now() bytes := t.BytesCompleted() - bytesUpload := t.Stats().DataBytesWritten + bytesUpload := t.Stats().BytesWrittenData dt := float32(now.Sub(oc.UpdatedAt)) // get the delta time length between now and last updated db := float32(bytes - oc.BytesCompleted) //getting the delta bytes rate := db * (float32(time.Second) / dt) // converting into seconds diff --git a/goTorrentWebUI/src/TopMenu/Modals/RSSModal/RSSModalLayout.js b/goTorrentWebUI/src/TopMenu/Modals/RSSModal/RSSModalLayout.js index c94b1965..83fd0194 100644 --- a/goTorrentWebUI/src/TopMenu/Modals/RSSModal/RSSModalLayout.js +++ b/goTorrentWebUI/src/TopMenu/Modals/RSSModal/RSSModalLayout.js @@ -89,7 +89,10 @@ const inlineStyle = { {i: 'b', x: 0, y: 1, w: 1, h: 5, static: true}, {i: 'c', x: 1, y: 1, w: 5, h: 5, minW: 5, minH: 3, static: true}, ]; - this.state = { layout }; + this.state = { + layout , + textValue: "", + }; }; @@ -103,7 +106,6 @@ const inlineStyle = { } handleAddRSSFeed = () => { - this.setState({ textValue: "Clear"}) //clearing out the text submitted let RSSURLSubmit = { MessageType: "addRSSFeed", Payload: [this.state.textValue] @@ -113,20 +115,13 @@ const inlineStyle = { MessageType: "rssFeedRequest", } ws.send(JSON.stringify(RSSRequest)) //Immediatly request an update of the feed when you add a new URL + this.setState({textValue: ""}) } setTextValue = (event) => { this.setState({ textValue: event.target.value }); } - - componentWillReceiveProps (nextProps) { - console.log("nextprops", nextProps, "Modal", nextProps.RSSModalOpen) - } - componentWillMount () { - console.log("Mounting grid") - } - render() { return (
diff --git a/goTorrentWebUI/src/TopMenu/Modals/deleteTorrentModal.js b/goTorrentWebUI/src/TopMenu/Modals/deleteTorrentModal.js index b655508b..9dfe5ec1 100644 --- a/goTorrentWebUI/src/TopMenu/Modals/deleteTorrentModal.js +++ b/goTorrentWebUI/src/TopMenu/Modals/deleteTorrentModal.js @@ -41,7 +41,7 @@ class DeleteTorrentModal extends React.Component { let selection = [] let deleteTorrentHashes = { MessageType: "deleteTorrents", - MessageDetail: "true", + MessageDetail: "false", //delete with data Payload: this.props.selectionHashes } console.log("Deleting Torrents", deleteTorrentHashes) @@ -56,7 +56,7 @@ class DeleteTorrentModal extends React.Component { let deleteTorrentHashes = { MessageType: "deleteTorrents", - MessageDetail: "true", + MessageDetail: "true", //delete with data Payload: this.props.selectionHashes, } console.log("Deleting Torrents and Data", deleteTorrentHashes) diff --git a/main.go b/main.go index f4a3d183..c8c88800 100644 --- a/main.go +++ b/main.go @@ -163,7 +163,7 @@ func main() { case "torrentFileListRequest": //client requested a filelist update Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested FileList Update") - FileListArray := Engine.CreateFileListArray(tclient, msg.Payload[0], db) + FileListArray := Engine.CreateFileListArray(tclient, msg.Payload[0], db, Config) conn.WriteJSON(FileListArray) //writing the JSON to the client case "torrentDetailedInfo": @@ -176,6 +176,21 @@ func main() { torrentPeerList := Engine.CreatePeerListArray(tclient, msg.Payload[0]) conn.WriteJSON(torrentPeerList) + case "fetchTorrentsByLabel": //TODO test this to make sure it works + Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested Torrents by Label") + label := msg.MessageDetail + torrentsByLabel := Storage.FetchTorrentsByLabel(db, label) + RunningTorrentArray = Engine.CreateRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) + labelRunningArray := []Engine.ClientDB{} + for _, torrent := range RunningTorrentArray { //Ranging over the running torrents and if the hashes match we have torrents by label + for _, label := range torrentsByLabel { + if torrent.TorrentHashString == label.Hash { + labelRunningArray = append(labelRunningArray, torrent) + } + } + } + conn.WriteJSON(labelRunningArray) + case "changeStorageValue": Logger.WithFields(logrus.Fields{"message": msg}).Debug("Client Requested Storage Location Update") newStorageLocation := msg.MessageDetail @@ -183,10 +198,16 @@ func main() { for _, singleHash := range hashes { singleTorrent := Storage.FetchTorrentFromStorage(db, singleHash) oldPath := singleTorrent.StoragePath - singleTorrent.StoragePath = newStorageLocation + newStorageLocationAbs, err := filepath.Abs(filepath.ToSlash(newStorageLocation)) + if err != nil { + Logger.WithFields(logrus.Fields{"patherr": err, "path": newStorageLocation}).Warn("Unable to create absolute path for storage location, using default") + singleTorrent.StoragePath = Config.TorrentConfig.DataDir + } else { + singleTorrent.StoragePath = newStorageLocationAbs + } Storage.UpdateStorageTick(db, singleTorrent) //push torrent to storage if singleTorrent.TorrentMoved == true { //If torrent has already been moved and I change path then move it again... TODO, does this work with symlinks? - Logger.WithFields(logrus.Fields{"message": msg}).Info("Torrent completed so moving to new location") + Logger.WithFields(logrus.Fields{"message": msg}).Info("Change Storage Value called") Engine.MoveAndLeaveSymlink(Config, singleHash, db, true, oldPath) } } @@ -283,7 +304,7 @@ func main() { } Logger.WithFields(logrus.Fields{"clientTorrent": clientTorrent, "magnetLink": magnetLink}).Info("Adding torrent to client!") Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "info", Payload: "Received MagnetLink"}, conn) - Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.TorrentConfig.DataDir, "magnet", "", storageValue, labelValue, Config.TFileUploadFolder) //starting the torrent and creating local DB entry + Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "magnet", "", storageValue, labelValue, Config) //starting the torrent and creating local DB entry } @@ -296,8 +317,6 @@ func main() { Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "error", Payload: "Unable to decode base64 string to file"}, conn) } FileName := msg.MessageDetail - fmt.Println("Full Message", msg.MessageType, msg.MessageDetail, msg.MessageDetailTwo, msg.MessageDetailThree) - fmt.Println("FileName", msg.MessageDetail) storageValue := msg.MessageDetailTwo labelValue := msg.MessageDetailThree if storageValue == "" { @@ -314,21 +333,22 @@ func main() { storageValue, _ = filepath.Abs(filepath.ToSlash(Config.DefaultMoveFolder)) } } - filePath := filepath.Join(Config.TFileUploadFolder, FileName) //creating a full filepath to store the .torrent files + filePath := filepath.Join(Config.TFileUploadFolder, FileName) + filePathAbs, err := filepath.Abs(filePath) //creating a full filepath to store the .torrent files - err = ioutil.WriteFile(filePath, file, 0755) //Dumping our received file into the filename + err = ioutil.WriteFile(filePathAbs, file, 0755) //Dumping our received file into the filename if err != nil { - Logger.WithFields(logrus.Fields{"filepath": filePath, "file Name": FileName, "Error": err}).Error("Unable to write torrent data to file") + Logger.WithFields(logrus.Fields{"filepath": filePathAbs, "file Name": FileName, "Error": err}).Error("Unable to write torrent data to file") Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "error", Payload: "Unable to write torrent data to file"}, conn) } - clientTorrent, err := tclient.AddTorrentFromFile(filePath) + clientTorrent, err := tclient.AddTorrentFromFile(filePathAbs) if err != nil { - Logger.WithFields(logrus.Fields{"filepath": filePath, "Error": err}).Error("Unable to add Torrent to torrent server") + Logger.WithFields(logrus.Fields{"filepath": filePathAbs, "Error": err}).Error("Unable to add Torrent to torrent server") Engine.CreateServerPushMessage(Engine.ServerPushMessage{MessageType: "serverPushMessage", MessageLevel: "error", Payload: "Unable to add Torrent to torrent server"}, conn) } - Logger.WithFields(logrus.Fields{"clienttorrent": clientTorrent.Name(), "filename": filePath}).Info("Added torrent") - Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, Config.TorrentConfig.DataDir, "file", filePath, storageValue, labelValue, Config.TFileUploadFolder) + Logger.WithFields(logrus.Fields{"clienttorrent": clientTorrent.Name(), "filename": filePathAbs}).Info("Added torrent") + Engine.StartTorrent(clientTorrent, torrentLocalStorage, db, "file", filePathAbs, storageValue, labelValue, Config) case "stopTorrents": TorrentListCommands := msg.Payload diff --git a/public/static/js/bundle.js b/public/static/js/bundle.js index 1e3c341f..10538700 100644 --- a/public/static/js/bundle.js +++ b/public/static/js/bundle.js @@ -97281,7 +97281,6 @@ var RSSModalLayout = function (_React$Component) { }; _this.handleAddRSSFeed = function () { - _this.setState({ textValue: "Clear" }); //clearing out the text submitted var RSSURLSubmit = { MessageType: "addRSSFeed", Payload: [_this.state.textValue] @@ -97291,6 +97290,7 @@ var RSSModalLayout = function (_React$Component) { MessageType: "rssFeedRequest" }; ws.send(JSON.stringify(RSSRequest)); //Immediatly request an update of the feed when you add a new URL + _this.setState({ textValue: "" }); }; _this.setTextValue = function (event) { @@ -97298,7 +97298,10 @@ var RSSModalLayout = function (_React$Component) { }; var layout = [{ i: 'a', x: 0, y: 0, w: 6, h: 1, static: true }, { i: 'b', x: 0, y: 1, w: 1, h: 5, static: true }, { i: 'c', x: 1, y: 1, w: 5, h: 5, minW: 5, minH: 3, static: true }]; - _this.state = { layout: layout }; + _this.state = { + layout: layout, + textValue: "" + }; return _this; } @@ -97308,16 +97311,6 @@ var RSSModalLayout = function (_React$Component) { value: function onLayoutChange(layout) { this.props.onLayoutChange(layout); } - }, { - key: 'componentWillReceiveProps', - value: function componentWillReceiveProps(nextProps) { - console.log("nextprops", nextProps, "Modal", nextProps.RSSModalOpen); - } - }, { - key: 'componentWillMount', - value: function componentWillMount() { - console.log("Mounting grid"); - } }, { key: 'render', value: function render() { @@ -116880,7 +116873,7 @@ var DeleteTorrentModal = function (_React$Component) { var selection = []; var deleteTorrentHashes = { MessageType: "deleteTorrents", - MessageDetail: "true", + MessageDetail: "false", //delete with data Payload: _this.props.selectionHashes }; console.log("Deleting Torrents", deleteTorrentHashes); @@ -116893,7 +116886,7 @@ var DeleteTorrentModal = function (_React$Component) { var deleteTorrentHashes = { MessageType: "deleteTorrents", - MessageDetail: "true", + MessageDetail: "true", //delete with data Payload: _this.props.selectionHashes }; console.log("Deleting Torrents and Data", deleteTorrentHashes); diff --git a/storage/storage.go b/storage/storage.go index abdfe2a3..f6655fcc 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -46,14 +46,15 @@ type TorrentLocal struct { Hash string `storm:"id,unique"` //Hash should be unique for every torrent... if not we are re-adding an already added torrent InfoBytes []byte DateAdded string - StoragePath string + StoragePath string //The absolute value of the path where the torrent will be moved when completed + TempStoragePath string //The absolute path of where the torrent is temporarily stored as it is downloaded TorrentMoved bool TorrentName string TorrentStatus string TorrentUploadLimit bool //if true this torrent will bypass the upload storage limit (effectively unlimited) MaxConnections int TorrentType string //magnet or .torrent file - TorrentFileName string //Should be absolute path + TorrentFileName string //Should be just the name of the torrent TorrentFile []byte Label string UploadedBytes int64 @@ -144,6 +145,22 @@ func FetchTorrentFromStorage(torrentStorage *storm.DB, selectedHash string) Torr return singleTorrentInfo } +//FetchTorrentsByLabel fetches a list of torrents that have a specific label +func FetchTorrentsByLabel(torrentStorage *storm.DB, label string) []TorrentLocal { + allTorrents := []*TorrentLocal{} + torrentsByLabel := []TorrentLocal{} + err := torrentStorage.All(&allTorrents) + if err != nil { + Logger.WithFields(logrus.Fields{"database": torrentStorage, "error": err}).Error("Unable to read Database into torrentLocalArray!") + } + for _, torrent := range allTorrents { + if torrent.Label == label { + torrentsByLabel = append(torrentsByLabel, *torrent) + } + } + return torrentsByLabel +} + //FetchHashHistory fetches the infohash of all torrents added into the client. The cron job checks this so as not to add torrents from RSS that were already added before func FetchHashHistory(db *storm.DB) TorrentHistoryList { torrentHistory := TorrentHistoryList{} diff --git a/torrentUpload/desktop.ini b/torrentUpload/desktop.ini new file mode 100644 index 00000000..141aa8bf --- /dev/null +++ b/torrentUpload/desktop.ini @@ -0,0 +1,3 @@ +[LocalizedFileNames] +Plan_9_from_Outer_Space_1959_archive.torrent=@Plan_9_from_Outer_Space_1959_archive.torrent,0 +Return_of_the_Street_Fighter.avi.torrent=@Return_of_the_Street_Fighter.avi.torrent,0