adding README and torrent file bits
This commit is contained in:
parent
0eb8ce1253
commit
89e4899841
3 changed files with 185 additions and 0 deletions
12
README.md
12
README.md
|
@ -0,0 +1,12 @@
|
|||
# go-bt
|
||||
|
||||
bittorrent related things
|
||||
|
||||
## ./bencode/
|
||||
|
||||
fork from code.google.com/p/bencode-go
|
||||
|
||||
## ./torrent/
|
||||
|
||||
Decoder and struct for the torrent file format
|
||||
|
59
example_loader.go
Normal file
59
example_loader.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/vbatts/go-bt/bencode"
|
||||
"github.com/vbatts/go-bt/torrent"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
flOutput = flag.String("o", "", "output the re-encoded torrent to file at this path")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if len(*flOutput) > 0 && flag.NArg() > 1 {
|
||||
fmt.Fprintf(os.Stderr, "-o and multiple input files can not be used together")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
for _, arg := range flag.Args() {
|
||||
fh, err := os.Open(arg)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := bencode.Decode(fh)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
fh.Close()
|
||||
continue
|
||||
}
|
||||
fh.Close()
|
||||
|
||||
tf, err := torrent.DecocdeTorrentData(data)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
fmt.Printf("Loaded: %s (%d files)\n", tf.Info.Name, len(tf.Info.Files))
|
||||
|
||||
if len(*flOutput) > 0 {
|
||||
fhOutput, err := os.Create(*flOutput)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
continue
|
||||
}
|
||||
err = bencode.Marshal(fhOutput, *tf)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
||||
}
|
||||
fmt.Printf("wrote: %s\n", fhOutput.Name())
|
||||
fhOutput.Close()
|
||||
}
|
||||
}
|
||||
}
|
114
torrent/file.go
Normal file
114
torrent/file.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
package torrent
|
||||
|
||||
import (
|
||||
//"github.com/vbatts/go-bt/bencode"
|
||||
"crypto/sha1"
|
||||
)
|
||||
|
||||
/*
|
||||
map[string]interface {}{"announce":"http://torrent.fedoraproject.org:6969/announce", "creation date":1387244350, "info":map[string]interface {}{"files":[]interface {}{map[string]interface {}{"length":1125, "path":[]interface {}{"Fedora-20-x86_64-CHECKSUM"}}, map[string]interface {}{"length":4603248640, "path":[]interface {}{"Fedora-20-x86_64-DVD.iso"}}}, "name":"Fedora-20-x86_64-DVD", "piece length":262144, "pieces":"m\x
|
||||
*/
|
||||
type File struct {
|
||||
// URL of a main tracker
|
||||
Announce string "announce"
|
||||
|
||||
// Epoch of the creation of this torrent
|
||||
CreationDate int64 "creation date"
|
||||
|
||||
// Dictionary about this torrent, including files to be tracked
|
||||
Info TorrentFileInfo "info"
|
||||
}
|
||||
|
||||
type TorrentFileInfo struct {
|
||||
// suggested file/directory name where the file(s) are to be saved
|
||||
Name string "name"
|
||||
|
||||
// hash list of joined SHA1 sums (160-bit length)
|
||||
Pieces string "pieces"
|
||||
|
||||
// number of bytes per piece
|
||||
PieceLength int64 "piece length"
|
||||
|
||||
// size of the file in bytes (only if this torrent is for a single file)
|
||||
Length int64 "length"
|
||||
|
||||
// list of information about the files
|
||||
Files []FileInfo "files"
|
||||
}
|
||||
|
||||
func (tfi TorrentFileInfo) PiecesList() []string {
|
||||
pieces := []string{}
|
||||
for i := 0; i < (len(tfi.Pieces) / sha1.Size); i++ {
|
||||
pieces = append(pieces, tfi.Pieces[i*sha1.Size:(i+1)*sha1.Size])
|
||||
}
|
||||
return pieces
|
||||
}
|
||||
|
||||
type FileInfo struct {
|
||||
// size of file in bytes
|
||||
Length int64 "length"
|
||||
|
||||
// list of strings corresponding to subdirectory names, the last of which is the actual file name
|
||||
Path []string "path"
|
||||
}
|
||||
|
||||
type torrentError struct {
|
||||
Msg string
|
||||
}
|
||||
func (te torrentError) Error() string {
|
||||
return te.Msg
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNotProperDataInterface = torrentError{"data does not look like map[string]interface{}"}
|
||||
)
|
||||
|
||||
func DecocdeTorrentData(data interface{}) (*File, error) {
|
||||
m, ok := data.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, ErrNotProperDataInterface
|
||||
}
|
||||
announce := m["announce"].(string)
|
||||
creationDate := m["creation date"].(int64)
|
||||
|
||||
info := m["info"].(map[string]interface{})
|
||||
pieceLength := info["piece length"].(int64)
|
||||
pieces := info["pieces"].(string)
|
||||
infoName := info["name"].(string)
|
||||
|
||||
isSingleFileTorrent := true
|
||||
infoFiles, ok := info["files"].([]interface{})
|
||||
if ok {
|
||||
isSingleFileTorrent = false
|
||||
}
|
||||
infoLength := int64(0)
|
||||
if isSingleFileTorrent {
|
||||
infoLength = info["length"].(int64)
|
||||
}
|
||||
files := []FileInfo{}
|
||||
if !isSingleFileTorrent {
|
||||
for _, fileInterface := range infoFiles {
|
||||
fileInfo := fileInterface.(map[string]interface{})
|
||||
paths := []string{}
|
||||
for _, path := range fileInfo["path"].([]interface{}) {
|
||||
paths = append(paths, path.(string))
|
||||
}
|
||||
files = append(files, FileInfo{
|
||||
Length: fileInfo["length"].(int64),
|
||||
Path: paths,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &File{
|
||||
Announce: announce,
|
||||
CreationDate: creationDate,
|
||||
Info: TorrentFileInfo{
|
||||
Name: infoName,
|
||||
Length: infoLength,
|
||||
Pieces: pieces,
|
||||
PieceLength: pieceLength,
|
||||
Files: files,
|
||||
},
|
||||
}, nil
|
||||
}
|
Loading…
Reference in a new issue