2017-12-26 16:25:10 +01:00
package main
import (
2017-12-29 18:26:13 +01:00
"bufio"
2019-04-19 11:45:31 +02:00
"bytes"
2017-12-29 18:26:13 +01:00
"fmt"
2018-04-02 12:17:50 +02:00
"github.com/fatih/color"
2018-04-12 16:10:22 +02:00
"github.com/go-ini/ini"
2020-04-04 15:58:29 +02:00
goflags "github.com/jessevdk/go-flags"
"github.com/rumanzo/bt2qbt/libtorrent"
"github.com/rumanzo/bt2qbt/replace"
2017-12-29 18:26:13 +01:00
"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"
2019-08-14 21:30:48 +02:00
"os/user"
2020-04-04 15:58:29 +02:00
"regexp"
2018-09-19 23:27:48 +02:00
"runtime"
2018-05-11 14:37:55 +02:00
"runtime/debug"
2017-12-27 21:43:12 +01:00
"strconv"
2018-04-02 12:17:50 +02:00
"strings"
2018-05-11 13:24:15 +02:00
"sync"
2018-05-11 13:35:20 +02:00
"time"
2017-12-26 16:25:10 +01:00
)
2020-02-16 11:36:24 +01:00
type Flags struct {
2020-04-04 15:58:29 +02:00
BitDir string ` short:"s" long:"source" description:"Source directory that contains resume.dat and torrents files" `
QBitDir string ` short:"d" long:"destination" description:"Destination directory BT_backup (as default)" `
2021-01-10 14:48:50 +01:00
Config string ` short:"c" long:"config" description:"qBittorrent config file (for write tags)" `
2020-04-04 15:58:29 +02:00
WithoutLabels bool ` long:"without-labels" description:"Do not export/import labels" `
WithoutTags bool ` long:"without-tags" description:"Do not export/import tags" `
2020-04-04 16:00:39 +02:00
SearchPaths [ ] string ` short:"t" long:"search" description:"Additional search path for torrents files\n Example: --search='/mnt/olddisk/savedtorrents' --search='/mnt/olddisk/workstorrents'" `
2020-04-04 16:15:16 +02:00
Replaces [ ] string ` short:"r" long:"replace" description:"Replace paths.\n Delimiter for from/to is comma - ,\n Example: -r \"D:\\films,/home/user/films\" -r \"D:\\music,/home/user/music\"\n" `
PathSeparator string ` long:"sep" description:"Default path separator that will use in all paths. You may need use this flag if you migrating from windows to linux in some cases" `
2020-02-16 11:36:24 +01:00
}
type Channels struct {
comChannel chan string
errChannel chan string
boundedChannel chan bool
}
2020-04-04 15:58:29 +02:00
func encodetorrentfile ( path string , newstructure * libtorrent . NewTorrentStructure ) error {
2020-02-16 11:36:24 +01:00
if _ , err := os . Stat ( path ) ; os . IsNotExist ( err ) {
os . Create ( path )
}
file , err := os . OpenFile ( path , os . O_WRONLY , 0666 )
if err != nil {
return err
}
defer file . Close ( )
bufferedWriter := bufio . NewWriter ( file )
enc := bencode . NewEncoder ( bufferedWriter )
if err := enc . Encode ( newstructure ) ; err != nil {
return err
}
bufferedWriter . Flush ( )
return nil
}
2018-05-13 23:40:36 +02:00
func ASCIIconvert ( s string ) string {
var buffer bytes . Buffer
2018-04-12 00:46:33 +02:00
for _ , c := range s {
if c > 127 {
2018-05-13 23:40:36 +02:00
buffer . WriteString ( ` \x ` + strconv . FormatUint ( uint64 ( c ) , 16 ) )
2018-04-12 00:46:33 +02:00
} else {
2018-05-13 23:40:36 +02:00
buffer . WriteString ( string ( c ) )
2018-04-12 00:46:33 +02:00
}
}
2018-05-13 23:40:36 +02:00
return buffer . String ( )
2018-04-12 00:46:33 +02:00
}
2018-04-13 17:16:38 +02:00
func checknotexists ( s string , tags [ ] string ) ( bool , string ) {
2018-04-12 00:46:33 +02:00
for _ , value := range tags {
if value == s {
2018-04-13 17:16:38 +02:00
return false , s
2018-04-12 00:46:33 +02:00
}
}
2018-04-13 17:16:38 +02:00
return true , s
2018-04-12 00:46:33 +02:00
}
2018-04-02 12:17:50 +02:00
func decodetorrentfile ( path string ) ( map [ string ] interface { } , error ) {
2017-12-26 16:25:10 +01:00
dat , err := ioutil . ReadFile ( path )
if err != nil {
2018-04-02 12:17:50 +02:00
return nil , err
2017-12-26 16:25:10 +01:00
}
var torrent map [ string ] interface { }
2020-02-16 11:36:24 +01:00
if err := bencode . DecodeBytes ( dat , & torrent ) ; err != nil {
2018-04-02 12:17:50 +02:00
return nil , err
2017-12-26 16:25:10 +01:00
}
2018-04-02 12:17:50 +02:00
return torrent , nil
2017-12-26 16:25:10 +01:00
}
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 {
return err
}
defer originalFile . Close ( )
newFile , err := os . Create ( dst )
if err != nil {
return err
}
defer newFile . Close ( )
if _ , err := io . Copy ( newFile , originalFile ) ; err != nil {
return err
}
2018-04-06 15:18:06 +02:00
if err := newFile . Sync ( ) ; err != nil {
2017-12-28 22:43:07 +01:00
return err
}
return nil
}
2020-02-16 11:36:24 +01:00
func logic ( key string , value map [ string ] interface { } , flags * Flags , chans * Channels , position int , wg * sync . WaitGroup ) error {
2018-05-11 13:24:15 +02:00
defer wg . Done ( )
2018-09-19 23:27:48 +02:00
defer func ( ) {
2020-02-16 11:36:24 +01:00
<- chans . boundedChannel
2018-09-19 23:27:48 +02:00
} ( )
2018-05-11 13:24:15 +02:00
defer func ( ) {
if r := recover ( ) ; r != nil {
2020-02-16 11:36:24 +01:00
chans . errChannel <- fmt . Sprintf (
2018-05-11 16:29:06 +02:00
"Panic while processing torrent %v:\n======\nReason: %v.\nText panic:\n%v\n======" ,
key , r , string ( debug . Stack ( ) ) )
2018-05-11 13:24:15 +02:00
}
} ( )
2018-04-18 13:29:45 +02:00
var err error
2020-04-15 22:59:03 +02:00
newstructure := libtorrent . NewTorrentStructure {
ActiveTime : 0 ,
AddedTime : 0 ,
Allocation : "sparse" ,
AutoManaged : 0 ,
CompletedTime : 0 ,
DownloadRateLimit : - 1 ,
FileFormat : "libtorrent resume file" ,
FileVersion : 1 ,
FinishedTime : 0 ,
LastDownload : 0 ,
LastSeenComplete : 0 ,
LastUpload : 0 ,
LibTorrentVersion : "1.2.5.0" ,
MaxConnections : 100 ,
MaxUploads : 100 ,
NumDownloaded : 0 ,
NumIncomplete : 0 ,
QbtQueuePosition : 1 ,
QbtRatioLimit : - 2000 ,
QbtSeedStatus : 1 ,
QbtSeedingTimeLimit : - 2 ,
QbttempPathDisabled : 0 ,
SeedMode : 0 ,
SeedingTime : 0 ,
SequentialDownload : 0 ,
SuperSeeding : 0 ,
StopWhenReady : 0 ,
TotalDownloaded : 0 ,
TotalUploaded : 0 ,
UploadRateLimit : 0 ,
QbtName : "" ,
WithoutLabels : flags . WithoutLabels ,
WithoutTags : flags . WithoutTags ,
Separator : flags . PathSeparator ,
}
2020-04-04 15:58:29 +02:00
2021-01-10 14:49:16 +01:00
if isAbs , _ := regexp . MatchString ( ` ^([A-Za-z]:)?\\ ` , key ) ; isAbs == true {
2020-04-04 15:58:29 +02:00
if runtime . GOOS == "windows" {
newstructure . TorrentFilePath = key
} else { // for unix system find in search paths
pathparts := strings . Split ( key , "\\" )
newstructure . TorrentFilePath = pathparts [ len ( pathparts ) - 1 ]
}
2018-05-10 22:07:59 +02:00
} else {
2020-04-04 15:58:29 +02:00
newstructure . TorrentFilePath = flags . BitDir + key // additional search required
2018-05-10 22:07:59 +02:00
}
2020-04-04 15:58:29 +02:00
if _ , err = os . Stat ( newstructure . TorrentFilePath ) ; os . IsNotExist ( err ) {
for _ , searchPath := range flags . SearchPaths {
if _ , err = os . Stat ( searchPath + newstructure . TorrentFilePath ) ; err == nil {
newstructure . TorrentFilePath = searchPath + newstructure . TorrentFilePath
goto CONTINUE
}
}
chans . errChannel <- fmt . Sprintf ( "Can't find torrent file %v for %v" , newstructure . TorrentFilePath , key )
2018-04-18 01:33:00 +02:00
return err
2020-04-04 15:58:29 +02:00
CONTINUE :
2018-04-18 01:33:00 +02:00
}
2020-04-04 15:58:29 +02:00
newstructure . TorrentFile , err = decodetorrentfile ( newstructure . TorrentFilePath )
2018-04-18 01:33:00 +02:00
if err != nil {
2020-04-04 15:58:29 +02:00
chans . errChannel <- fmt . Sprintf ( "Can't decode torrent file %v for %v" , newstructure . TorrentFilePath , key )
2018-04-18 01:33:00 +02:00
return err
}
2020-02-16 12:58:26 +01:00
2020-04-04 15:58:29 +02:00
for _ , str := range flags . Replaces {
patterns := strings . Split ( str , "," )
newstructure . Replace = append ( newstructure . Replace , replace . Replace {
From : patterns [ 0 ] ,
To : patterns [ 1 ] ,
} )
2020-02-16 12:58:26 +01:00
}
2020-04-04 15:58:29 +02:00
if _ , ok := newstructure . TorrentFile [ "info" ] . ( map [ string ] interface { } ) [ "files" ] ; ok {
newstructure . HasFiles = true
2018-04-18 01:33:00 +02:00
} else {
2020-04-04 15:58:29 +02:00
newstructure . HasFiles = false
2018-04-18 01:33:00 +02:00
}
if value [ "path" ] . ( string ) [ len ( value [ "path" ] . ( string ) ) - 1 ] == os . PathSeparator {
2020-04-04 15:58:29 +02:00
newstructure . Path = value [ "path" ] . ( string ) [ : len ( value [ "path" ] . ( string ) ) - 1 ]
2018-04-18 14:03:13 +02:00
} else {
2020-04-04 15:58:29 +02:00
newstructure . Path = value [ "path" ] . ( string )
2018-04-18 01:33:00 +02:00
}
2021-01-10 14:51:35 +01:00
// if torrent name was renamed, add modified name
if value [ "caption" ] != nil {
newstructure . QbtName = value [ "caption" ] . ( string )
}
2020-02-16 11:36:24 +01:00
newstructure . ActiveTime = value [ "runtime" ] . ( int64 )
newstructure . AddedTime = value [ "added_on" ] . ( int64 )
newstructure . CompletedTime = value [ "completed_on" ] . ( int64 )
2020-04-04 15:58:29 +02:00
newstructure . InfoHash = value [ "info" ] . ( string )
2020-02-16 11:36:24 +01:00
newstructure . SeedingTime = value [ "runtime" ] . ( int64 )
2020-04-04 15:58:29 +02:00
newstructure . QbtQueuePosition = position
newstructure . Started ( value [ "started" ] . ( int64 ) )
2020-02-16 11:36:24 +01:00
newstructure . FinishedTime = int64 ( time . Since ( time . Unix ( value [ "completed_on" ] . ( int64 ) , 0 ) ) . Minutes ( ) )
newstructure . TotalDownloaded = value [ "downloaded" ] . ( int64 )
newstructure . TotalUploaded = value [ "uploaded" ] . ( int64 )
newstructure . UploadRateLimit = value [ "upspeed" ] . ( int64 )
2020-04-04 15:58:29 +02:00
newstructure . IfTags ( value [ "labels" ] )
2018-04-18 13:29:45 +02:00
if value [ "label" ] != nil {
2020-04-04 15:58:29 +02:00
newstructure . IfLabel ( value [ "label" ] . ( string ) )
2018-04-18 13:29:45 +02:00
} else {
2020-04-04 15:58:29 +02:00
newstructure . IfLabel ( "" )
2018-04-18 13:29:45 +02:00
}
2020-04-04 15:58:29 +02:00
newstructure . GetTrackers ( value [ "trackers" ] )
newstructure . PrioConvert ( value [ "prio" ] . ( string ) )
2018-05-11 16:29:06 +02:00
// https://libtorrent.org/manual-ref.html#fast-resume
2020-04-04 15:58:29 +02:00
newstructure . PieceLenght = newstructure . TorrentFile [ "info" ] . ( map [ string ] interface { } ) [ "piece length" ] . ( int64 )
2018-05-11 16:29:06 +02:00
2018-05-06 17:35:32 +02:00
/ *
2018-05-08 18:10:02 +02:00
pieces maps to a string whose length is a multiple of 20. It is to be subdivided into strings of length 20 ,
each of which is the SHA1 hash of the piece at the corresponding index .
http : //www.bittorrent.org/beps/bep_0003.html
2018-05-06 17:35:32 +02:00
* /
2020-04-04 15:58:29 +02:00
newstructure . NumPieces = int64 ( len ( newstructure . TorrentFile [ "info" ] . ( map [ string ] interface { } ) [ "pieces" ] . ( string ) ) ) / 20
newstructure . FillMissing ( )
newbasename := newstructure . GetHash ( )
2018-04-18 13:29:45 +02:00
2020-04-04 15:58:29 +02:00
if err = encodetorrentfile ( flags . QBitDir + newbasename + ".fastresume" , & newstructure ) ; err != nil {
chans . errChannel <- fmt . Sprintf ( "Can't create qBittorrent fastresume file %v" , flags . QBitDir + newbasename + ".fastresume" )
2018-04-02 12:17:50 +02:00
return err
2017-12-28 22:43:07 +01:00
}
2020-04-04 15:58:29 +02:00
if err = copyfile ( newstructure . TorrentFilePath , flags . QBitDir + newbasename + ".torrent" ) ; err != nil {
chans . errChannel <- fmt . Sprintf ( "Can't create qBittorrent torrent file %v" , flags . QBitDir + newbasename + ".torrent" )
2018-04-02 12:17:50 +02:00
return err
2017-12-28 22:43:07 +01:00
}
2020-02-16 11:36:24 +01:00
chans . comChannel <- fmt . Sprintf ( "Sucessfully imported %v" , key )
2018-04-02 12:17:50 +02:00
return nil
2017-12-26 16:25:10 +01:00
}
func main ( ) {
2020-04-04 15:58:29 +02:00
flags := Flags { PathSeparator : string ( os . PathSeparator ) }
2019-08-14 21:30:48 +02:00
sep := string ( os . PathSeparator )
switch OS := runtime . GOOS ; OS {
case "windows" :
2020-04-04 15:58:29 +02:00
flags . BitDir = os . Getenv ( "APPDATA" ) + sep + "uTorrent" + sep
flags . Config = os . Getenv ( "APPDATA" ) + sep + "qBittorrent" + sep + "qBittorrent.ini"
flags . QBitDir = os . Getenv ( "LOCALAPPDATA" ) + sep + "qBittorrent" + sep + "BT_backup" + sep
2020-02-16 13:07:16 +01:00
case "linux" :
usr , err := user . Current ( )
if err != nil {
panic ( err )
}
2020-04-04 15:58:29 +02:00
flags . BitDir = "/mnt/uTorrent/"
flags . Config = usr . HomeDir + sep + ".config" + sep + "qBittorrent" + sep + "qBittorrent.conf"
flags . QBitDir = usr . HomeDir + sep + ".local" + sep + "share" + sep + "data" + sep + "qBittorrent" + sep + "BT_backup" + sep
2019-08-14 21:30:48 +02:00
case "darwin" :
usr , err := user . Current ( )
if err != nil {
panic ( err )
}
2020-04-04 15:58:29 +02:00
flags . BitDir = usr . HomeDir + sep + "Library" + sep + "Application Support" + sep + "uTorrent" + sep
flags . Config = usr . HomeDir + sep + ".config" + sep + "qBittorrent" + sep + "qbittorrent.ini"
flags . QBitDir = usr . HomeDir + sep + "Library" + sep + "Application Support" + sep + "QBittorrent" + sep + "BT_backup" + sep
2019-08-14 21:30:48 +02:00
}
2020-04-04 15:58:29 +02:00
if _ , err := goflags . Parse ( & flags ) ; err != nil { // https://godoc.org/github.com/jessevdk/go-flags#ErrorType
if flagsErr , ok := err . ( * goflags . Error ) ; ok && flagsErr . Type == goflags . ErrHelp {
os . Exit ( 0 )
} else {
log . Println ( err )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
}
2018-04-09 12:09:59 +02:00
2020-04-04 15:58:29 +02:00
if len ( flags . Replaces ) != 0 {
for _ , str := range flags . Replaces {
2020-02-16 12:58:26 +01:00
patterns := strings . Split ( str , "," )
if len ( patterns ) < 2 {
log . Println ( "Bad replace pattern" )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
}
}
2020-04-04 15:58:29 +02:00
if flags . BitDir [ len ( flags . BitDir ) - 1 ] != os . PathSeparator {
flags . BitDir += string ( os . PathSeparator )
2018-04-09 12:09:59 +02:00
}
2020-04-04 15:58:29 +02:00
if flags . QBitDir [ len ( flags . QBitDir ) - 1 ] != os . PathSeparator {
flags . QBitDir += string ( os . PathSeparator )
}
for index , searchPath := range flags . SearchPaths {
if searchPath [ len ( searchPath ) - 1 ] != os . PathSeparator {
flags . SearchPaths [ index ] += string ( os . PathSeparator )
}
2018-04-09 12:09:59 +02:00
}
2020-04-04 15:58:29 +02:00
if _ , err := os . Stat ( flags . BitDir ) ; os . IsNotExist ( err ) {
2018-04-02 12:17:50 +02:00
log . Println ( "Can't find uTorrent\\Bittorrent folder" )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
2020-10-26 21:33:08 +01:00
flags . SearchPaths = append ( flags . SearchPaths , flags . BitDir )
2020-04-04 15:58:29 +02:00
if _ , err := os . Stat ( flags . QBitDir ) ; os . IsNotExist ( err ) {
2018-04-02 12:17:50 +02:00
log . Println ( "Can't find qBittorrent folder" )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
2020-04-04 15:58:29 +02:00
resumefilepath := flags . BitDir + "resume.dat"
2018-04-02 12:17:50 +02:00
if _ , err := os . Stat ( resumefilepath ) ; os . IsNotExist ( err ) {
log . Println ( "Can't find uTorrent\\Bittorrent resume file" )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
resumefile , err := decodetorrentfile ( resumefilepath )
if err != nil {
log . Println ( "Can't decode uTorrent\\Bittorrent resume file" )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
2020-04-04 15:58:29 +02:00
if flags . WithoutTags == false {
if _ , err := os . Stat ( flags . Config ) ; os . IsNotExist ( err ) {
2018-05-11 16:29:06 +02:00
fmt . Println ( "Can not read qBittorrent config file. Try run and close qBittorrent if you have not done" +
" so already, or specify the path explicitly or do not import tags" )
2018-04-12 16:10:22 +02:00
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
2018-04-12 00:46:33 +02:00
}
2020-04-04 15:58:29 +02:00
totaljobs := len ( resumefile )
chans := Channels { comChannel : make ( chan string , totaljobs ) ,
errChannel : make ( chan string , totaljobs ) ,
boundedChannel : make ( chan bool , runtime . GOMAXPROCS ( 0 ) * 2 ) }
color . Green ( "It will be performed processing from directory %v to directory %v\n" , flags . BitDir , flags . QBitDir )
2018-05-11 16:29:06 +02:00
color . HiRed ( "Check that the qBittorrent is turned off and the directory %v and config %v is backed up.\n\n" ,
2020-04-04 15:58:29 +02:00
flags . QBitDir , flags . Config )
2018-04-02 12:17:50 +02:00
fmt . Println ( "Press Enter to start" )
2018-04-18 14:26:29 +02:00
fmt . Scanln ( )
2018-05-10 22:09:40 +02:00
log . Println ( "Started" )
2020-04-04 15:58:29 +02:00
transfertorrents ( chans , flags , resumefile , totaljobs )
fmt . Println ( "\nPress Enter to exit" )
fmt . Scanln ( )
}
func transfertorrents ( chans Channels , flags Flags , resumefile map [ string ] interface { } , totaljobs int ) {
2018-04-11 19:49:24 +02:00
numjob := 1
2018-04-12 16:10:22 +02:00
var oldtags string
var newtags [ ] string
2018-05-11 13:24:15 +02:00
var wg sync . WaitGroup
2020-04-04 15:58:29 +02:00
2018-05-11 13:44:46 +02:00
positionnum := 0
2018-04-02 12:17:50 +02:00
for key , value := range resumefile {
2017-12-27 22:00:50 +01:00
if key != ".fileguard" && key != "rec" {
2018-05-11 13:44:46 +02:00
positionnum ++
2020-04-04 15:58:29 +02:00
if flags . WithoutTags == false {
2018-05-29 09:47:45 +02:00
if labels , ok := value . ( map [ string ] interface { } ) [ "labels" ] ; ok {
for _ , label := range labels . ( [ ] interface { } ) {
if len ( label . ( string ) ) > 0 {
if ok , tag := checknotexists ( ASCIIconvert ( label . ( string ) ) , newtags ) ; ok {
newtags = append ( newtags , tag )
}
2018-04-12 16:10:22 +02:00
}
}
}
}
2018-05-11 13:24:15 +02:00
wg . Add ( 1 )
2020-02-16 11:36:24 +01:00
chans . boundedChannel <- true
go logic ( key , value . ( map [ string ] interface { } ) , & flags , & chans , positionnum , & wg )
2019-04-19 11:45:31 +02:00
} else {
totaljobs --
2017-12-26 16:25:10 +01:00
}
}
2018-05-11 13:35:20 +02:00
go func ( ) {
2018-05-11 13:24:15 +02:00
wg . Wait ( )
2020-02-16 11:36:24 +01:00
close ( chans . comChannel )
close ( chans . errChannel )
2018-05-11 13:24:15 +02:00
} ( )
2020-02-16 11:36:24 +01:00
for message := range chans . comChannel {
2018-04-02 12:17:50 +02:00
fmt . Printf ( "%v/%v %v \n" , numjob , totaljobs , message )
numjob ++
2018-05-11 13:24:15 +02:00
}
2018-07-31 17:44:25 +02:00
var waserrors bool
2020-02-16 11:36:24 +01:00
for message := range chans . errChannel {
2018-05-11 13:24:15 +02:00
fmt . Printf ( "%v/%v %v \n" , numjob , totaljobs , message )
2018-07-31 17:44:25 +02:00
waserrors = true
2018-05-11 20:43:48 +02:00
numjob ++
2018-04-02 12:17:50 +02:00
}
2020-04-04 15:58:29 +02:00
if flags . WithoutTags == false {
cfg , err := ini . Load ( flags . Config )
2018-04-12 16:10:22 +02:00
ini . PrettyFormat = false
ini . PrettySection = false
if err != nil {
fmt . Println ( "Can not read qBittorrent config file. Try to specify the path explicitly or do not import tags" )
time . Sleep ( 30 * time . Second )
os . Exit ( 1 )
}
if _ , err := cfg . GetSection ( "BitTorrent" ) ; err != nil {
cfg . NewSection ( "BitTorrent" )
2018-04-12 00:46:33 +02:00
2018-04-12 16:10:22 +02:00
//Dirty hack for section order. Sorry
kv := cfg . Section ( "Network" ) . KeysHash ( )
cfg . DeleteSection ( "Network" )
cfg . NewSection ( "Network" )
for key , value := range kv {
cfg . Section ( "Network" ) . NewKey ( key , value )
}
//End of dirty hack
}
if cfg . Section ( "BitTorrent" ) . HasKey ( "Session\\Tags" ) {
oldtags = cfg . Section ( "BitTorrent" ) . Key ( "Session\\Tags" ) . String ( )
for _ , tag := range strings . Split ( oldtags , ", " ) {
2018-04-13 17:16:38 +02:00
if ok , t := checknotexists ( tag , newtags ) ; ok {
newtags = append ( newtags , t )
2018-04-12 16:10:22 +02:00
}
}
cfg . Section ( "BitTorrent" ) . Key ( "Session\\Tags" ) . SetValue ( strings . Join ( newtags , ", " ) )
} else {
cfg . Section ( "BitTorrent" ) . NewKey ( "Session\\Tags" , strings . Join ( newtags , ", " ) )
2018-04-12 00:46:33 +02:00
}
2020-04-04 15:58:29 +02:00
cfg . SaveTo ( flags . Config )
2018-04-12 00:46:33 +02:00
}
2018-05-11 13:24:15 +02:00
fmt . Println ( )
2018-05-10 22:09:40 +02:00
log . Println ( "Ended" )
2018-07-31 17:44:25 +02:00
if waserrors {
2018-05-11 13:24:15 +02:00
log . Println ( "Not all torrents was processed" )
}
2020-02-11 23:10:35 +01:00
}