2017-05-06 13:43:24 +02:00
package metainfo
// this file is from https://github.com/majestrate/XD
import (
"crypto/sha1"
"github.com/zeebo/bencode"
"io"
"os"
"path/filepath"
)
type FilePath [ ] string
// get filepath
func ( f FilePath ) FilePath ( ) string {
return filepath . Join ( f ... )
}
/** open file using base path */
func ( f FilePath ) Open ( base string ) ( * os . File , error ) {
return os . OpenFile ( filepath . Join ( base , f . FilePath ( ) ) , os . O_RDWR | os . O_CREATE , 0600 )
}
type FileInfo struct {
// length of file
Length uint64 ` bencode:"length" `
// relative path of file
Path FilePath ` bencode:"path" `
// md5sum
Sum [ ] byte ` bencode:"md5sum,omitempty" `
}
// info section of torrent file
type Info struct {
// length of pices in bytes
PieceLength uint32 ` bencode:"piece length" `
// piece data
Pieces [ ] byte ` bencode:"pieces" `
// name of root file
Path string ` bencode:"name" `
// file metadata
Files [ ] FileInfo ` bencode:"files,omitempty" `
// private torrent
Private * int64 ` bencode:"private,omitempty" `
// length of file in signle file mode
Length uint64 ` bencode:"length,omitempty" `
// md5sum
Sum [ ] byte ` bencode:"md5sum,omitempty" `
}
// get fileinfos from this info section
func ( i Info ) GetFiles ( ) ( infos [ ] FileInfo ) {
if i . Length > 0 {
infos = append ( infos , FileInfo {
Length : i . Length ,
Path : FilePath ( [ ] string { i . Path } ) ,
Sum : i . Sum ,
} )
} else {
infos = append ( infos , i . Files ... )
}
return
}
func ( i Info ) NumPieces ( ) uint32 {
return uint32 ( len ( i . Pieces ) / 20 )
}
// a torrent file
type TorrentFile struct {
Info Info ` bencode:"info" `
Announce string ` bencode:"announce" `
AnnounceList [ ] [ ] string ` bencode:"announce-list" `
Created uint64 ` bencode:"created" `
Comment [ ] byte ` bencode:"comment" `
CreatedBy [ ] byte ` bencode:"created by" `
Encoding [ ] byte ` bencode:"encoding" `
}
// get total size of files from torrent info section
func ( tf * TorrentFile ) TotalSize ( ) uint64 {
if tf . IsSingleFile ( ) {
return tf . Info . Length
}
total := uint64 ( 0 )
for _ , f := range tf . Info . Files {
total += f . Length
}
return total
}
func ( tf * TorrentFile ) GetAllAnnounceURLS ( ) ( l [ ] string ) {
if len ( tf . Announce ) > 0 {
l = append ( l , tf . Announce )
}
for _ , al := range tf . AnnounceList {
for _ , a := range al {
if len ( a ) > 0 {
l = append ( l , a )
}
}
}
return
}
func ( tf * TorrentFile ) TorrentName ( ) string {
return string ( tf . Info . Path )
}
// return true if this torrent is private otherwise return false
func ( tf * TorrentFile ) IsPrivate ( ) bool {
2017-05-07 12:20:08 +02:00
return tf . Info . Private != nil && * tf . Info . Private == 1
2017-05-06 13:43:24 +02:00
}
// calculate infohash
func ( tf * TorrentFile ) Infohash ( ) ( ih [ 20 ] byte ) {
s := sha1 . New ( )
enc := bencode . NewEncoder ( s )
enc . Encode ( & tf . Info )
d := s . Sum ( nil )
copy ( ih [ : ] , d [ : ] )
return
}
// return true if this torrent is for a single file
func ( tf * TorrentFile ) IsSingleFile ( ) bool {
return tf . Info . Length > 0
}
// bencode this file via an io.Writer
func ( tf * TorrentFile ) Encode ( w io . Writer ) ( err error ) {
enc := bencode . NewEncoder ( w )
err = enc . Encode ( tf )
return
}
// load from an io.Reader
func ( tf * TorrentFile ) Decode ( r io . Reader ) ( err error ) {
dec := bencode . NewDecoder ( r )
err = dec . Decode ( tf )
return
}