2017-12-26 16:25:10 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2017-12-29 18:26:13 +01:00
|
|
|
"bufio"
|
2017-12-26 16:25:10 +01:00
|
|
|
"crypto/sha1"
|
|
|
|
"encoding/hex"
|
2017-12-29 18:26:13 +01:00
|
|
|
"fmt"
|
|
|
|
"github.com/zeebo/bencode"
|
2017-12-26 16:25:10 +01:00
|
|
|
"io"
|
2017-12-29 18:26:13 +01:00
|
|
|
"io/ioutil"
|
2017-12-26 21:56:32 +01:00
|
|
|
"log"
|
2017-12-29 18:26:13 +01:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2017-12-27 21:43:12 +01:00
|
|
|
"strconv"
|
2017-12-29 18:26:13 +01:00
|
|
|
"sync"
|
2017-12-28 14:28:16 +01:00
|
|
|
"time"
|
2017-12-30 16:17:58 +01:00
|
|
|
//"github.com/juju/gnuflag"
|
2017-12-26 16:25:10 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
func decodetorrentfile(path string) map[string]interface{} {
|
|
|
|
dat, err := ioutil.ReadFile(path)
|
|
|
|
if err != nil {
|
2017-12-26 21:56:32 +01:00
|
|
|
log.Fatal(err)
|
2017-12-26 16:25:10 +01:00
|
|
|
}
|
|
|
|
var torrent map[string]interface{}
|
|
|
|
if err := bencode.DecodeBytes([]byte(dat), &torrent); err != nil {
|
2017-12-26 21:56:32 +01:00
|
|
|
log.Fatal(err)
|
2017-12-26 16:25:10 +01:00
|
|
|
}
|
|
|
|
return torrent
|
|
|
|
}
|
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
func encodetorrentfile(path string, newstructure map[string]interface{}) error {
|
2017-12-26 21:56:32 +01:00
|
|
|
_, err := os.Stat(path)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
os.Create(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
file, err := os.OpenFile(path, os.O_WRONLY, 0666)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
2017-12-28 21:19:46 +01:00
|
|
|
return err
|
2017-12-26 21:56:32 +01:00
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
bufferedWriter := bufio.NewWriter(file)
|
|
|
|
enc := bencode.NewEncoder(bufferedWriter)
|
2017-12-30 16:17:58 +01:00
|
|
|
if err := enc.Encode(newstructure); err != nil {
|
2017-12-26 21:56:32 +01:00
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
bufferedWriter.Flush()
|
2017-12-28 21:19:46 +01:00
|
|
|
return nil
|
2017-12-26 21:56:32 +01:00
|
|
|
}
|
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
func gethash(info map[string]interface{}) (hash string) {
|
|
|
|
torinfo, _ := bencode.EncodeString(info)
|
2017-12-26 16:25:10 +01:00
|
|
|
h := sha1.New()
|
|
|
|
io.WriteString(h, torinfo)
|
2017-12-28 21:19:46 +01:00
|
|
|
hash = hex.EncodeToString(h.Sum(nil))
|
|
|
|
return
|
2017-12-26 16:25:10 +01:00
|
|
|
}
|
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
func piecesconvert(s string) []byte {
|
2017-12-30 16:20:59 +01:00
|
|
|
var newpieces = make([]byte, 0 , len(s) * 8)
|
2017-12-30 16:17:58 +01:00
|
|
|
for _, c := range []byte(s) {
|
2017-12-29 18:26:13 +01:00
|
|
|
var binString string
|
|
|
|
binString = fmt.Sprintf("%s%.8b", binString, c)
|
|
|
|
for _, d := range binString {
|
2017-12-27 21:43:12 +01:00
|
|
|
chr, _ := strconv.Atoi(string(d))
|
|
|
|
newpieces = append(newpieces, byte(chr))
|
|
|
|
}
|
2017-12-27 17:34:58 +01:00
|
|
|
}
|
2017-12-30 16:17:58 +01:00
|
|
|
return newpieces
|
2017-12-27 17:34:58 +01:00
|
|
|
}
|
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
func prioconvert(src string) (newprio []int) {
|
|
|
|
for _, c := range []byte(src) {
|
2017-12-29 18:26:13 +01:00
|
|
|
if i := int(c); (i == 0) || (i == 128) { // if not selected
|
2017-12-28 21:19:46 +01:00
|
|
|
newprio = append(newprio, 0)
|
2017-12-29 18:26:13 +01:00
|
|
|
} else if (i == 4) || (i == 8) { // if low or normal prio
|
2017-12-28 21:19:46 +01:00
|
|
|
newprio = append(newprio, 1)
|
2017-12-29 18:26:13 +01:00
|
|
|
} else if i == 12 { // if high prio
|
2017-12-28 21:19:46 +01:00
|
|
|
newprio = append(newprio, 6)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-12-29 18:26:13 +01:00
|
|
|
func fmtime(path string) (mtime int64) {
|
2017-12-28 21:19:46 +01:00
|
|
|
fi, err := os.Stat(path)
|
|
|
|
if err != nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
mtime = int64(fi.ModTime().Unix())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2017-12-29 18:26:13 +01:00
|
|
|
func copyfile(src string, dst string) error {
|
2017-12-28 22:43:07 +01:00
|
|
|
originalFile, err := os.Open(src)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer originalFile.Close()
|
|
|
|
|
|
|
|
newFile, err := os.Create(dst)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer newFile.Close()
|
|
|
|
|
|
|
|
if _, err := io.Copy(newFile, originalFile); err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = newFile.Sync()
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
func logic(key string, value map[string]interface{}, bitdir *string, wg *sync.WaitGroup, with_label *bool, with_tags *bool, qbitdir *string) {
|
2017-12-26 16:25:10 +01:00
|
|
|
defer wg.Done()
|
2017-12-26 21:56:32 +01:00
|
|
|
newstructure := map[string]interface{}{"active_time": 0, "added_time": 0, "announce_to_dht": 0,
|
|
|
|
"announce_to_lsd": 0, "announce_to_trackers": 0, "auto_managed": 0,
|
|
|
|
"banned_peers": new(string), "banned_peers6": new(string), "blocks per piece": 0,
|
2017-12-28 21:19:46 +01:00
|
|
|
"completed_time": 0, "download_rate_limit": -1, "file sizes": new([][]int64),
|
2017-12-28 14:28:16 +01:00
|
|
|
"file-format": "libtorrent resume file", "file-version": 1, "file_priority": new([]int), "finished_time": 0,
|
2017-12-26 21:56:32 +01:00
|
|
|
"info-hash": new([]byte), "last_seen_complete": 0, "libtorrent-version": "1.1.5.0",
|
2017-12-28 14:28:16 +01:00
|
|
|
"max_connections": 100, "max_uploads": 100, "num_complete": 0, "num_downloaded": 0,
|
2017-12-26 21:56:32 +01:00
|
|
|
"num_incomplete": 0, "paused": 0, "peers": new(string), "peers6": new(string),
|
|
|
|
"pieces": new([]byte), "qBt-category": new(string), "qBt-hasRootFolder": 0, "qBt-name": new(string),
|
|
|
|
"qBt-queuePosition": 0, "qBt-ratioLimit": 0, "qBt-savePath": new(string),
|
|
|
|
"qBt-seedStatus": 1, "qBt-seedingTimeLimit": -2, "qBt-tags": new([]string),
|
|
|
|
"qBt-tempPathDisabled": 0, "save_path": new(string), "seed_mode": 0, "seeding_time": 0,
|
|
|
|
"sequential_download": 0, "super_seeding": 0, "total_downloaded": 0,
|
|
|
|
"total_uploadedv": 0, "trackers": new([][]string), "upload_rate_limit": 0,
|
2017-12-26 18:55:39 +01:00
|
|
|
}
|
2017-12-26 16:25:10 +01:00
|
|
|
torrentfile := decodetorrentfile(*bitdir + key)
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["active_time"] = value["runtime"]
|
|
|
|
newstructure["added_time"] = value["added_on"]
|
|
|
|
newstructure["completed_time"] = value["completed_on"]
|
|
|
|
newstructure["info-hash"] = value["info"]
|
|
|
|
newstructure["qBt-tags"] = value["labels"]
|
|
|
|
newstructure["blocks per piece"] = torrentfile["info"].(map[string]interface{})["piece length"].(int64) / value["blocksize"].(int64)
|
|
|
|
newstructure["pieces"] = piecesconvert(value["have"].(string))
|
|
|
|
newstructure["seeding_time"] = value["runtime"]
|
|
|
|
if newstructure["paused"] = 0; value["started"] == 0 {
|
2017-12-29 18:26:13 +01:00
|
|
|
newstructure["paused"] = 1
|
|
|
|
}
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["finished_time"] = int(time.Since(time.Unix(value["completed_on"].(int64), 0)).Minutes())
|
|
|
|
if value["completed_on"] != 0 {
|
2017-12-29 18:26:13 +01:00
|
|
|
newstructure["last_seen_complete"] = int(time.Now().Unix())
|
|
|
|
}
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["total_downloaded"] = value["downloaded"]
|
|
|
|
newstructure["total_uploaded"] = value["uploaded"]
|
|
|
|
newstructure["upload_rate_limit"] = value["upspeed"]
|
2017-12-29 18:26:13 +01:00
|
|
|
if *with_label == true {
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["qBt-category"] = value["label"]
|
2017-12-29 18:26:13 +01:00
|
|
|
}
|
|
|
|
if *with_tags == true {
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["qBt-tags"] = value["labels"]
|
2017-12-29 18:26:13 +01:00
|
|
|
}
|
|
|
|
var trackers []interface{}
|
2017-12-30 16:17:58 +01:00
|
|
|
for _, tracker := range value["trackers"].([]interface{}) {
|
2017-12-29 18:26:13 +01:00
|
|
|
trackers = append(trackers, tracker)
|
|
|
|
}
|
|
|
|
newstructure["trackers"] = trackers
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["file_priority"] = prioconvert(value["prio"].(string))
|
2017-12-28 22:10:57 +01:00
|
|
|
if files, ok := torrentfile["info"].(map[string]interface{})["files"]; ok {
|
|
|
|
var filelists []interface{}
|
|
|
|
for num, file := range files.([]interface{}) {
|
|
|
|
var lenght, mtime int64
|
|
|
|
filename := file.(map[string]interface{})["path"].([]interface{})[0].(string)
|
2017-12-30 16:17:58 +01:00
|
|
|
fullpath := value["path"].(string) + "\\" + filename
|
2017-12-28 22:10:57 +01:00
|
|
|
if n := newstructure["file_priority"].([]int)[num]; n != 0 {
|
|
|
|
lenght = file.(map[string]interface{})["length"].(int64)
|
|
|
|
mtime = fmtime(fullpath)
|
2017-12-29 18:26:13 +01:00
|
|
|
} else {
|
|
|
|
lenght, mtime = 0, 0
|
|
|
|
}
|
2017-12-28 22:10:57 +01:00
|
|
|
flenmtime := []int64{lenght, mtime}
|
|
|
|
filelists = append(filelists, flenmtime)
|
|
|
|
}
|
|
|
|
newstructure["file sizes"] = filelists
|
2017-12-28 21:19:46 +01:00
|
|
|
} else {
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["file sizes"] = [][]int64{{torrentfile["info"].(map[string]interface{})["length"].(int64), fmtime(value["path"].(string))}}
|
2017-12-28 21:19:46 +01:00
|
|
|
}
|
2017-12-30 16:17:58 +01:00
|
|
|
newstructure["save_path"] = filepath.Dir(value["path"].(string)) + "\\"
|
2017-12-28 22:10:57 +01:00
|
|
|
newstructure["qBt-savePath"] = newstructure["save_path"]
|
2017-12-29 18:26:13 +01:00
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
newbasename := gethash(torrentfile["info"].(map[string]interface{}))
|
2017-12-29 18:26:13 +01:00
|
|
|
|
2017-12-30 16:17:58 +01:00
|
|
|
if err := encodetorrentfile(*qbitdir+newbasename+".fastresume", newstructure); err != nil {
|
2017-12-28 22:43:07 +01:00
|
|
|
fmt.Println(err)
|
|
|
|
}
|
2017-12-29 18:26:13 +01:00
|
|
|
if err := copyfile(*bitdir+key, *qbitdir+newbasename+".torrent"); err != nil {
|
2017-12-28 22:43:07 +01:00
|
|
|
fmt.Println(err)
|
|
|
|
}
|
2017-12-26 16:25:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
bitdir := "C:/Users/rumanzo/AppData/Roaming/BitTorrent/"
|
2017-12-29 18:26:13 +01:00
|
|
|
qbitdir := "C:/Users/rumanzo/AppData/Local/qBittorrent/BT_backup/"
|
2017-12-28 22:10:57 +01:00
|
|
|
torrent := decodetorrentfile(bitdir + "resume.dat")
|
2017-12-28 14:28:16 +01:00
|
|
|
var with_label, with_tags bool
|
|
|
|
with_label, with_tags = true, true
|
2017-12-26 16:25:10 +01:00
|
|
|
for key, value := range torrent {
|
2017-12-27 22:00:50 +01:00
|
|
|
if key != ".fileguard" && key != "rec" {
|
2017-12-26 16:25:10 +01:00
|
|
|
wg.Add(1)
|
2017-12-30 16:17:58 +01:00
|
|
|
go logic(key, value.(map[string]interface{}), &bitdir, &wg, &with_label, &with_tags, &qbitdir)
|
2017-12-26 16:25:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2017-12-29 18:26:13 +01:00
|
|
|
|
|
|
|
//TODO fix pieces.
|