mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
refactor and update
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
type TorrentDB struct {
|
type TorrentDB struct {
|
||||||
*torrent.TorrentSpec
|
*torrent.TorrentSpec
|
||||||
|
|
||||||
|
Name string `json:"name"`
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
Poster string `json:"poster,omitempty"`
|
Poster string `json:"poster,omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -12,15 +12,26 @@ type Viewed struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SetViewed(vv *Viewed) {
|
func SetViewed(vv *Viewed) {
|
||||||
|
var indexes map[int]struct{}
|
||||||
|
var err error
|
||||||
|
|
||||||
buf := tdb.Get("Viewed", vv.Hash)
|
buf := tdb.Get("Viewed", vv.Hash)
|
||||||
var indeces map[int]struct{}
|
if len(buf) == 0 {
|
||||||
err := json.Unmarshal(buf, &indeces)
|
indexes = make(map[int]struct{})
|
||||||
if err == nil {
|
indexes[vv.FileIndex] = struct{}{}
|
||||||
indeces[vv.FileIndex] = struct{}{}
|
buf, err = json.Marshal(indexes)
|
||||||
buf, err = json.Marshal(indeces)
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tdb.Set("Viewed", vv.Hash, buf)
|
tdb.Set("Viewed", vv.Hash, buf)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
err = json.Unmarshal(buf, &indexes)
|
||||||
|
if err == nil {
|
||||||
|
indexes[vv.FileIndex] = struct{}{}
|
||||||
|
buf, err = json.Marshal(indexes)
|
||||||
|
if err == nil {
|
||||||
|
tdb.Set("Viewed", vv.Hash, buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.TLogln("Error set viewed:", err)
|
log.TLogln("Error set viewed:", err)
|
||||||
@@ -65,7 +76,7 @@ func ListViewed(hash string) []*Viewed {
|
|||||||
err = json.Unmarshal(buf, &indeces)
|
err = json.Unmarshal(buf, &indeces)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for i, _ := range indeces {
|
for i, _ := range indeces {
|
||||||
ret = append(ret, &Viewed{hash, i})
|
ret = append(ret, &Viewed{key, i})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
src/server/torr/apihelper.go
Normal file
88
src/server/torr/apihelper.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package torr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/anacrolix/torrent"
|
||||||
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
|
"server/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
bts *BTServer
|
||||||
|
)
|
||||||
|
|
||||||
|
func InitApiHelper(bt *BTServer) {
|
||||||
|
bts = bt
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddTorrent(spec *torrent.TorrentSpec, title, poster string) (*Torrent, error) {
|
||||||
|
torr, err := NewTorrent(spec, bts)
|
||||||
|
if err != nil {
|
||||||
|
log.TLogln("error add torrent:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !torr.GotInfo() {
|
||||||
|
log.TLogln("error add torrent:", "timeout connection torrent")
|
||||||
|
return nil, errors.New("timeout connection torrent")
|
||||||
|
}
|
||||||
|
|
||||||
|
torr.Title = title
|
||||||
|
torr.Poster = poster
|
||||||
|
|
||||||
|
if torr.Title == "" {
|
||||||
|
torr.Title = torr.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
return torr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveTorrentToDB(torr *Torrent) {
|
||||||
|
log.TLogln("save to db:", torr.Hash())
|
||||||
|
AddTorrentDB(torr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTorrent(hashHex string) *Torrent {
|
||||||
|
hash := metainfo.NewHashFromHex(hashHex)
|
||||||
|
tor := bts.GetTorrent(hash)
|
||||||
|
if tor == nil {
|
||||||
|
tor = GetTorrentDB(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tor
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemTorrent(hashHex string) {
|
||||||
|
hash := metainfo.NewHashFromHex(hashHex)
|
||||||
|
bts.RemoveTorrent(hash)
|
||||||
|
RemTorrentDB(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListTorrent() []*Torrent {
|
||||||
|
btlist := bts.ListTorrents()
|
||||||
|
dblist := ListTorrentsDB()
|
||||||
|
|
||||||
|
for hash, t := range dblist {
|
||||||
|
if _, ok := btlist[hash]; !ok {
|
||||||
|
btlist[hash] = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ret []*Torrent
|
||||||
|
|
||||||
|
for _, t := range btlist {
|
||||||
|
ret = append(ret, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(ret, func(i, j int) bool {
|
||||||
|
return ret[i].Timestamp > ret[j].Timestamp
|
||||||
|
})
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func DropTorrent(hashHex string) {
|
||||||
|
hash := metainfo.NewHashFromHex(hashHex)
|
||||||
|
bts.RemoveTorrent(hash)
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ func (bt *BTServer) Connect() error {
|
|||||||
bt.configure()
|
bt.configure()
|
||||||
bt.client, err = torrent.NewClient(bt.config)
|
bt.client, err = torrent.NewClient(bt.config)
|
||||||
bt.torrents = make(map[metainfo.Hash]*Torrent)
|
bt.torrents = make(map[metainfo.Hash]*Torrent)
|
||||||
|
InitApiHelper(bt)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,10 +110,10 @@ func (bt *BTServer) GetTorrent(hash torrent.InfoHash) *Torrent {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bt *BTServer) ListTorrents() []*Torrent {
|
func (bt *BTServer) ListTorrents() map[metainfo.Hash]*Torrent {
|
||||||
var list []*Torrent
|
list := make(map[metainfo.Hash]*Torrent)
|
||||||
for _, t := range bt.torrents {
|
for k, v := range bt.torrents {
|
||||||
list = append(list, t)
|
list[k] = v
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
package utils
|
package torr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"server/settings"
|
"server/settings"
|
||||||
"server/torr"
|
|
||||||
"server/torr/state"
|
"server/torr/state"
|
||||||
|
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
func AddTorrent(torr *torr.Torrent) {
|
func AddTorrentDB(torr *Torrent) {
|
||||||
t := new(settings.TorrentDB)
|
t := new(settings.TorrentDB)
|
||||||
t.TorrentSpec = torr.TorrentSpec
|
t.TorrentSpec = torr.TorrentSpec
|
||||||
|
t.Name = torr.Name()
|
||||||
t.Title = torr.Title
|
t.Title = torr.Title
|
||||||
t.Poster = torr.Poster
|
t.Poster = torr.Poster
|
||||||
t.Timestamp = time.Now().Unix()
|
t.Timestamp = time.Now().Unix()
|
||||||
t.Files = torr.Stats().FileStats
|
t.Files = torr.Status().FileStats
|
||||||
settings.AddTorrent(t)
|
settings.AddTorrent(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTorrent(hash metainfo.Hash) *torr.Torrent {
|
func GetTorrentDB(hash metainfo.Hash) *Torrent {
|
||||||
list := settings.ListTorrent()
|
list := settings.ListTorrent()
|
||||||
for _, db := range list {
|
for _, db := range list {
|
||||||
if hash == db.InfoHash {
|
if hash == db.InfoHash {
|
||||||
torr := new(torr.Torrent)
|
torr := new(Torrent)
|
||||||
torr.TorrentSpec = db.TorrentSpec
|
torr.TorrentSpec = db.TorrentSpec
|
||||||
torr.Title = db.Title
|
torr.Title = db.Title
|
||||||
torr.Poster = db.Poster
|
torr.Poster = db.Poster
|
||||||
torr.Status = state.TorrentInDB
|
torr.Stat = state.TorrentInDB
|
||||||
return torr
|
return torr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemTorrent(hash metainfo.Hash) {
|
func RemTorrentDB(hash metainfo.Hash) {
|
||||||
settings.RemTorrent(hash)
|
settings.RemTorrent(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListTorrents() []*torr.Torrent {
|
func ListTorrentsDB() map[metainfo.Hash]*Torrent {
|
||||||
var ret []*torr.Torrent
|
ret := make(map[metainfo.Hash]*Torrent)
|
||||||
list := settings.ListTorrent()
|
list := settings.ListTorrent()
|
||||||
for _, db := range list {
|
for _, db := range list {
|
||||||
torr := new(torr.Torrent)
|
torr := new(Torrent)
|
||||||
torr.TorrentSpec = db.TorrentSpec
|
torr.TorrentSpec = db.TorrentSpec
|
||||||
torr.Title = db.Title
|
torr.Title = db.Title
|
||||||
torr.Poster = db.Poster
|
torr.Poster = db.Poster
|
||||||
torr.Status = state.TorrentInDB
|
torr.Stat = state.TorrentInDB
|
||||||
ret = append(ret, torr)
|
ret[torr.TorrentSpec.InfoHash] = torr
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package state
|
package state
|
||||||
|
|
||||||
type TorrentStatus int
|
type TorrentStat int
|
||||||
|
|
||||||
func (t TorrentStatus) String() string {
|
func (t TorrentStat) String() string {
|
||||||
switch t {
|
switch t {
|
||||||
case TorrentAdded:
|
case TorrentAdded:
|
||||||
return "Torrent added"
|
return "Torrent added"
|
||||||
@@ -22,7 +22,7 @@ func (t TorrentStatus) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TorrentAdded = TorrentStatus(iota)
|
TorrentAdded = TorrentStat(iota)
|
||||||
TorrentGettingInfo
|
TorrentGettingInfo
|
||||||
TorrentPreload
|
TorrentPreload
|
||||||
TorrentWorking
|
TorrentWorking
|
||||||
@@ -30,15 +30,16 @@ const (
|
|||||||
TorrentInDB
|
TorrentInDB
|
||||||
)
|
)
|
||||||
|
|
||||||
type TorrentStats struct {
|
type TorrentStatus struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Poster string `json:"poster"`
|
Poster string `json:"poster"`
|
||||||
|
Timestamp int64 `json:"timestamp"`
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Hash string `json:"hash,omitempty"`
|
Hash string `json:"hash,omitempty"`
|
||||||
|
|
||||||
TorrentStatus TorrentStatus `json:"torrent_status,omitempty"`
|
Stat TorrentStat `json:"stat"`
|
||||||
TorrentStatusString string `json:"torrent_status_string,omitempty"`
|
StatString string `json:"stat_string"`
|
||||||
|
|
||||||
LoadedSize int64 `json:"loaded_size,omitempty"`
|
LoadedSize int64 `json:"loaded_size,omitempty"`
|
||||||
TorrentSize int64 `json:"torrent_size,omitempty"`
|
TorrentSize int64 `json:"torrent_size,omitempty"`
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/anacrolix/missinggo/httptoo"
|
"github.com/anacrolix/missinggo/httptoo"
|
||||||
|
sets "server/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Torrent) Stream(fileIndex int, req *http.Request, resp http.ResponseWriter) error {
|
func (t *Torrent) Stream(fileIndex int, req *http.Request, resp http.ResponseWriter) error {
|
||||||
@@ -20,6 +21,8 @@ func (t *Torrent) Stream(fileIndex int, req *http.Request, resp http.ResponseWri
|
|||||||
|
|
||||||
log.Println("Connect client")
|
log.Println("Connect client")
|
||||||
|
|
||||||
|
sets.SetViewed(&sets.Viewed{t.Hash().HexString(), fileIndex})
|
||||||
|
|
||||||
resp.Header().Set("Connection", "close")
|
resp.Header().Set("Connection", "close")
|
||||||
resp.Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", t.Hash().HexString(), file.Path())))
|
resp.Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", t.Hash().HexString(), file.Path())))
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ type Torrent struct {
|
|||||||
Poster string
|
Poster string
|
||||||
*torrent.TorrentSpec
|
*torrent.TorrentSpec
|
||||||
|
|
||||||
Status state.TorrentStatus
|
Stat state.TorrentStat
|
||||||
|
Timestamp int64
|
||||||
/////
|
/////
|
||||||
|
|
||||||
*torrent.Torrent
|
*torrent.Torrent
|
||||||
@@ -50,7 +51,6 @@ type Torrent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewTorrent(spec *torrent.TorrentSpec, bt *BTServer) (*Torrent, error) {
|
func NewTorrent(spec *torrent.TorrentSpec, bt *BTServer) (*Torrent, error) {
|
||||||
|
|
||||||
switch settings.BTsets.RetrackersMode {
|
switch settings.BTsets.RetrackersMode {
|
||||||
case 1:
|
case 1:
|
||||||
spec.Trackers = append(spec.Trackers, [][]string{utils.GetDefTrackers()}...)
|
spec.Trackers = append(spec.Trackers, [][]string{utils.GetDefTrackers()}...)
|
||||||
@@ -73,12 +73,13 @@ func NewTorrent(spec *torrent.TorrentSpec, bt *BTServer) (*Torrent, error) {
|
|||||||
|
|
||||||
torr := new(Torrent)
|
torr := new(Torrent)
|
||||||
torr.Torrent = goTorrent
|
torr.Torrent = goTorrent
|
||||||
torr.Status = state.TorrentAdded
|
torr.Stat = state.TorrentAdded
|
||||||
torr.lastTimeSpeed = time.Now()
|
torr.lastTimeSpeed = time.Now()
|
||||||
torr.bt = bt
|
torr.bt = bt
|
||||||
torr.closed = goTorrent.Closed()
|
torr.closed = goTorrent.Closed()
|
||||||
torr.TorrentSpec = spec
|
torr.TorrentSpec = spec
|
||||||
torr.expiredTime = time.Now().Add(time.Minute)
|
torr.expiredTime = time.Now().Add(time.Minute)
|
||||||
|
torr.Timestamp = time.Now().Unix()
|
||||||
|
|
||||||
go torr.watch()
|
go torr.watch()
|
||||||
|
|
||||||
@@ -106,12 +107,12 @@ func (t *Torrent) WaitInfo() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) GotInfo() bool {
|
func (t *Torrent) GotInfo() bool {
|
||||||
if t.Status == state.TorrentClosed {
|
if t.Stat == state.TorrentClosed {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
t.Status = state.TorrentGettingInfo
|
t.Stat = state.TorrentGettingInfo
|
||||||
if t.WaitInfo() {
|
if t.WaitInfo() {
|
||||||
t.Status = state.TorrentWorking
|
t.Stat = state.TorrentWorking
|
||||||
t.expiredTime = time.Now().Add(time.Minute * 5)
|
t.expiredTime = time.Now().Add(time.Minute * 5)
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@@ -179,7 +180,7 @@ func (t *Torrent) updateRA() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) expired() bool {
|
func (t *Torrent) expired() bool {
|
||||||
return t.cache.ReadersLen() == 0 && t.expiredTime.Before(time.Now()) && (t.Status == state.TorrentWorking || t.Status == state.TorrentClosed)
|
return t.cache.ReadersLen() == 0 && t.expiredTime.Before(time.Now()) && (t.Stat == state.TorrentWorking || t.Stat == state.TorrentClosed)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) Files() []*torrent.File {
|
func (t *Torrent) Files() []*torrent.File {
|
||||||
@@ -208,7 +209,7 @@ func (t *Torrent) Length() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) NewReader(file *torrent.File, readahead int64) *Reader {
|
func (t *Torrent) NewReader(file *torrent.File, readahead int64) *Reader {
|
||||||
if t.Status == state.TorrentClosed {
|
if t.Stat == state.TorrentClosed {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
reader := NewReader(t, file, readahead)
|
reader := NewReader(t, file, readahead)
|
||||||
@@ -230,14 +231,14 @@ func (t *Torrent) Preload(index int, size int64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.Status == state.TorrentGettingInfo {
|
if t.Stat == state.TorrentGettingInfo {
|
||||||
t.WaitInfo()
|
t.WaitInfo()
|
||||||
// wait change status
|
// wait change status
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.muTorrent.Lock()
|
t.muTorrent.Lock()
|
||||||
if t.Status != state.TorrentWorking {
|
if t.Stat != state.TorrentWorking {
|
||||||
t.muTorrent.Unlock()
|
t.muTorrent.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -249,12 +250,12 @@ func (t *Torrent) Preload(index int, size int64) {
|
|||||||
t.muTorrent.Unlock()
|
t.muTorrent.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.Status = state.TorrentPreload
|
t.Stat = state.TorrentPreload
|
||||||
t.muTorrent.Unlock()
|
t.muTorrent.Unlock()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if t.Status == state.TorrentPreload {
|
if t.Stat == state.TorrentPreload {
|
||||||
t.Status = state.TorrentWorking
|
t.Stat = state.TorrentWorking
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -299,7 +300,7 @@ func (t *Torrent) Preload(index int, size int64) {
|
|||||||
t.PreloadSize = size
|
t.PreloadSize = size
|
||||||
var lastSize int64 = 0
|
var lastSize int64 = 0
|
||||||
errCount := 0
|
errCount := 0
|
||||||
for t.Status == state.TorrentPreload {
|
for t.Stat == state.TorrentPreload {
|
||||||
t.expiredTime = time.Now().Add(time.Minute * 5)
|
t.expiredTime = time.Now().Add(time.Minute * 5)
|
||||||
t.PreloadedBytes = t.Torrent.BytesCompleted()
|
t.PreloadedBytes = t.Torrent.BytesCompleted()
|
||||||
log.TLogln("Preload:", file.Torrent().InfoHash().HexString(), utils2.Format(float64(t.PreloadedBytes)), "/", utils2.Format(float64(t.PreloadSize)), "Speed:", utils2.Format(t.DownloadSpeed), "Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
|
log.TLogln("Preload:", file.Torrent().InfoHash().HexString(), utils2.Format(float64(t.PreloadedBytes)), "/", utils2.Format(float64(t.PreloadSize)), "Speed:", utils2.Format(t.DownloadSpeed), "Peers:[", t.Torrent.Stats().ConnectedSeeders, "]", t.Torrent.Stats().ActivePeers, "/", t.Torrent.Stats().TotalPeers)
|
||||||
@@ -330,7 +331,7 @@ func (t *Torrent) drop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) Close() {
|
func (t *Torrent) Close() {
|
||||||
t.Status = state.TorrentClosed
|
t.Stat = state.TorrentClosed
|
||||||
t.bt.mu.Lock()
|
t.bt.mu.Lock()
|
||||||
defer t.bt.mu.Unlock()
|
defer t.bt.mu.Unlock()
|
||||||
|
|
||||||
@@ -341,16 +342,17 @@ func (t *Torrent) Close() {
|
|||||||
t.drop()
|
t.drop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Torrent) Stats() *state.TorrentStats {
|
func (t *Torrent) Status() *state.TorrentStatus {
|
||||||
t.muTorrent.Lock()
|
t.muTorrent.Lock()
|
||||||
defer t.muTorrent.Unlock()
|
defer t.muTorrent.Unlock()
|
||||||
|
|
||||||
st := new(state.TorrentStats)
|
st := new(state.TorrentStatus)
|
||||||
|
|
||||||
st.TorrentStatus = t.Status
|
st.Stat = t.Stat
|
||||||
st.TorrentStatusString = t.Status.String()
|
st.StatString = t.Stat.String()
|
||||||
st.Title = t.Title
|
st.Title = t.Title
|
||||||
st.Poster = t.Poster
|
st.Poster = t.Poster
|
||||||
|
st.Timestamp = t.Timestamp
|
||||||
|
|
||||||
if t.TorrentSpec != nil {
|
if t.TorrentSpec != nil {
|
||||||
st.Hash = t.TorrentSpec.InfoHash.HexString()
|
st.Hash = t.TorrentSpec.InfoHash.HexString()
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func GetMimeType(filename string) string {
|
|||||||
return "*/*"
|
return "*/*"
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPlayableFiles(st state.TorrentStats) []state.TorrentFileStat {
|
func GetPlayableFiles(st state.TorrentStatus) []state.TorrentFileStat {
|
||||||
files := make([]state.TorrentFileStat, 0)
|
files := make([]state.TorrentFileStat, 0)
|
||||||
for _, f := range st.FileStats {
|
for _, f := range st.FileStats {
|
||||||
if GetMimeType(f.Path) != "*/*" {
|
if GetMimeType(f.Path) != "*/*" {
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/anacrolix/missinggo/httptoo"
|
||||||
sets "server/settings"
|
sets "server/settings"
|
||||||
|
"server/torr"
|
||||||
"server/torr/state"
|
"server/torr/state"
|
||||||
"server/utils"
|
"server/utils"
|
||||||
|
|
||||||
@@ -18,21 +20,17 @@ import (
|
|||||||
|
|
||||||
func allPlayList(c *gin.Context) {
|
func allPlayList(c *gin.Context) {
|
||||||
_, fromlast := c.GetQuery("fromlast")
|
_, fromlast := c.GetQuery("fromlast")
|
||||||
stats := listTorrents()
|
torrs := torr.ListTorrent()
|
||||||
|
|
||||||
host := "http://" + c.Request.Host
|
host := "http://" + c.Request.Host
|
||||||
list := "#EXTM3U\n"
|
list := "#EXTM3U\n"
|
||||||
|
hash := ""
|
||||||
for _, stat := range stats {
|
for _, tr := range torrs {
|
||||||
list += getM3uList(stat, host, fromlast)
|
list += getM3uList(tr.Status(), host, fromlast)
|
||||||
|
hash += tr.Hash().HexString()
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Header("Content-Type", "audio/x-mpegurl")
|
sendM3U(c, "all.m3u", hash, list)
|
||||||
c.Header("Connection", "close")
|
|
||||||
c.Header("Content-Disposition", `attachment; filename="all.m3u"`)
|
|
||||||
http.ServeContent(c.Writer, c.Request, "all.m3u", time.Now(), bytes.NewReader([]byte(list)))
|
|
||||||
|
|
||||||
c.Status(200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func playList(c *gin.Context) {
|
func playList(c *gin.Context) {
|
||||||
@@ -43,34 +41,43 @@ func playList(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stats := listTorrents()
|
tors := torr.ListTorrent()
|
||||||
var stat *state.TorrentStats
|
var tor *torr.Torrent
|
||||||
for _, st := range stats {
|
for _, tr := range tors {
|
||||||
if st.Hash == hash {
|
if tr.Hash().HexString() == hash {
|
||||||
stat = st
|
tor = tr
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if stat == nil {
|
if tor == nil {
|
||||||
c.AbortWithStatus(http.StatusNotFound)
|
c.AbortWithStatus(http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO проверить
|
// TODO проверить
|
||||||
host := "http://" + c.Request.Host
|
host := "http://" + c.Request.Host
|
||||||
list := getM3uList(stat, host, fromlast)
|
list := getM3uList(tor.Status(), host, fromlast)
|
||||||
list = "#EXTM3U\n" + list
|
list = "#EXTM3U\n" + list
|
||||||
|
|
||||||
|
sendM3U(c, tor.Name()+".m3u", tor.Hash().HexString(), list)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendM3U(c *gin.Context, name, hash string, m3u string) {
|
||||||
c.Header("Content-Type", "audio/x-mpegurl")
|
c.Header("Content-Type", "audio/x-mpegurl")
|
||||||
c.Header("Connection", "close")
|
c.Header("Connection", "close")
|
||||||
c.Header("Content-Disposition", `attachment; filename="playlist.m3u"`)
|
if hash != "" {
|
||||||
http.ServeContent(c.Writer, c.Request, "playlist.m3u", time.Now(), bytes.NewReader([]byte(list)))
|
c.Header("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", hash, name)))
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
name = "playlist.m3u"
|
||||||
|
}
|
||||||
|
c.Header("Content-Disposition", `attachment; filename="`+name+`"`)
|
||||||
|
http.ServeContent(c.Writer, c.Request, name, time.Now(), bytes.NewReader([]byte(m3u)))
|
||||||
c.Status(200)
|
c.Status(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getM3uList(tor *state.TorrentStats, host string, fromLast bool) string {
|
func getM3uList(tor *state.TorrentStatus, host string, fromLast bool) string {
|
||||||
m3u := ""
|
m3u := ""
|
||||||
from := 0
|
from := 0
|
||||||
if fromLast {
|
if fromLast {
|
||||||
@@ -87,15 +94,20 @@ func getM3uList(tor *state.TorrentStats, host string, fromLast bool) string {
|
|||||||
fn = f.Path
|
fn = f.Path
|
||||||
}
|
}
|
||||||
m3u += "#EXTINF:0," + fn + "\n"
|
m3u += "#EXTINF:0," + fn + "\n"
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&index=0&play
|
title := filepath.Base(f.Path)
|
||||||
m3u += host + "/stream/" + url.QueryEscape(f.Path) + "?link=" + tor.Hash + "&file=" + fmt.Sprint(f.Id) + "\n"
|
if tor.Title != "" {
|
||||||
|
title = tor.Title
|
||||||
|
} else if tor.Name != "" {
|
||||||
|
title = tor.Name
|
||||||
|
}
|
||||||
|
m3u += host + "/stream/" + url.PathEscape(title) + "?link=" + tor.Hash + "&index=" + fmt.Sprint(f.Id) + "&play\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m3u
|
return m3u
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchLastPlayed(tor *state.TorrentStats) int {
|
func searchLastPlayed(tor *state.TorrentStatus) int {
|
||||||
//TODO проверить
|
//TODO проверить
|
||||||
viewed := sets.ListViewed(tor.Hash)
|
viewed := sets.ListViewed(tor.Hash)
|
||||||
for i := len(tor.FileStats); i > 0; i-- {
|
for i := len(tor.FileStats); i > 0; i-- {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func SetupRouteApi(route *gin.Engine, serv *torr.BTServer) {
|
|||||||
route.POST("/settings", settings)
|
route.POST("/settings", settings)
|
||||||
|
|
||||||
route.POST("/torrents", torrents)
|
route.POST("/torrents", torrents)
|
||||||
|
route.POST("/torrent/upload", torrentUpload)
|
||||||
|
|
||||||
route.GET("/stream", stream)
|
route.GET("/stream", stream)
|
||||||
route.GET("/stream/*fname", stream)
|
route.GET("/stream/*fname", stream)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"server/torr"
|
"server/torr"
|
||||||
"server/web/api/utils"
|
"server/web/api/utils"
|
||||||
@@ -12,12 +13,17 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&index=1&stat
|
// get stat
|
||||||
|
// http://127.0.0.1:8090/stream/fname?link=...&stat
|
||||||
|
// get m3u
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&index=1&m3u
|
// http://127.0.0.1:8090/stream/fname?link=...&index=1&m3u
|
||||||
|
// http://127.0.0.1:8090/stream/fname?link=...&index=1&m3u&fromlast
|
||||||
|
// stream torrent
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&index=1&play
|
// http://127.0.0.1:8090/stream/fname?link=...&index=1&play
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&save&title=...&poster=...
|
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&index=1&play&save
|
// http://127.0.0.1:8090/stream/fname?link=...&index=1&play&save
|
||||||
// http://127.0.0.1:8090/stream/fname?link=...&index=1&play&save&title=...&poster=...
|
// http://127.0.0.1:8090/stream/fname?link=...&index=1&play&save&title=...&poster=...
|
||||||
|
// only save
|
||||||
|
// http://127.0.0.1:8090/stream/fname?link=...&save&title=...&poster=...
|
||||||
|
|
||||||
func stream(c *gin.Context) {
|
func stream(c *gin.Context) {
|
||||||
link := c.Query("link")
|
link := c.Query("link")
|
||||||
@@ -26,6 +32,7 @@ func stream(c *gin.Context) {
|
|||||||
_, stat := c.GetQuery("stat")
|
_, stat := c.GetQuery("stat")
|
||||||
_, save := c.GetQuery("save")
|
_, save := c.GetQuery("save")
|
||||||
_, m3u := c.GetQuery("m3u")
|
_, m3u := c.GetQuery("m3u")
|
||||||
|
_, fromlast := c.GetQuery("fromlast")
|
||||||
_, play := c.GetQuery("play")
|
_, play := c.GetQuery("play")
|
||||||
title := c.Query("title")
|
title := c.Query("title")
|
||||||
poster := c.Query("poster")
|
poster := c.Query("poster")
|
||||||
@@ -37,10 +44,13 @@ func stream(c *gin.Context) {
|
|||||||
|
|
||||||
if title == "" {
|
if title == "" {
|
||||||
title = c.Param("fname")
|
title = c.Param("fname")
|
||||||
|
title, _ = url.PathUnescape(title)
|
||||||
|
title = strings.TrimLeft(title, "/")
|
||||||
|
} else {
|
||||||
|
title, _ = url.QueryUnescape(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
link, _ = url.QueryUnescape(link)
|
link, _ = url.QueryUnescape(link)
|
||||||
title, _ = url.QueryUnescape(title)
|
|
||||||
poster, _ = url.QueryUnescape(poster)
|
poster, _ = url.QueryUnescape(poster)
|
||||||
|
|
||||||
spec, err := utils.ParseLink(link)
|
spec, err := utils.ParseLink(link)
|
||||||
@@ -49,43 +59,16 @@ func stream(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var tor *torr.Torrent
|
tor, err := torr.AddTorrent(spec, title, poster)
|
||||||
|
if err != nil {
|
||||||
// find torrent in bts
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
for _, torrent := range bts.ListTorrents() {
|
return
|
||||||
if torrent.Hash().HexString() == spec.InfoHash.HexString() {
|
|
||||||
tor = torrent
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// find in db
|
|
||||||
for _, torrent := range utils.ListTorrents() {
|
|
||||||
if torrent.Hash().HexString() == spec.InfoHash.HexString() {
|
|
||||||
tor = torrent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add torrent to bts
|
|
||||||
if tor != nil {
|
|
||||||
tor, err = torr.NewTorrent(tor.TorrentSpec, bts)
|
|
||||||
} else {
|
|
||||||
tor, err = torr.NewTorrent(spec, bts)
|
|
||||||
if err != nil {
|
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tor.Title = title
|
|
||||||
tor.Poster = poster
|
|
||||||
|
|
||||||
// save to db
|
// save to db
|
||||||
if save {
|
if save {
|
||||||
utils.AddTorrent(tor)
|
torr.SaveTorrentToDB(tor)
|
||||||
c.Status(200)
|
c.Status(200) // only set status, not return
|
||||||
}
|
|
||||||
// wait torrent info
|
|
||||||
if !tor.GotInfo() {
|
|
||||||
c.AbortWithError(http.StatusInternalServerError, errors.New("timeout torrent get info"))
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// find file
|
// find file
|
||||||
@@ -98,7 +81,7 @@ func stream(c *gin.Context) {
|
|||||||
index = ind
|
index = ind
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if index == -1 {
|
if index == -1 && play { // if file index not set and play file exec
|
||||||
c.AbortWithError(http.StatusBadRequest, errors.New("\"index\" is empty or wrong"))
|
c.AbortWithError(http.StatusBadRequest, errors.New("\"index\" is empty or wrong"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -107,14 +90,14 @@ func stream(c *gin.Context) {
|
|||||||
tor.Preload(index, 0)
|
tor.Preload(index, 0)
|
||||||
}
|
}
|
||||||
// return stat if query
|
// return stat if query
|
||||||
if stat || (!m3u && !play) {
|
if stat {
|
||||||
c.JSON(200, tor.Stats())
|
c.JSON(200, tor.Status())
|
||||||
return
|
return
|
||||||
} else
|
} else
|
||||||
// return m3u if query
|
// return m3u if query
|
||||||
if m3u {
|
if m3u {
|
||||||
//TODO m3u
|
m3ulist := "#EXTM3U\n" + getM3uList(tor.Status(), "http://"+c.Request.Host, fromlast)
|
||||||
c.JSON(200, tor.Stats())
|
sendM3U(c, tor.Name(), tor.Hash().HexString(), m3ulist)
|
||||||
return
|
return
|
||||||
} else
|
} else
|
||||||
// return play if query
|
// return play if query
|
||||||
@@ -123,96 +106,3 @@ func stream(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
func torrentPlay(c echo.Context) error {
|
|
||||||
link := c.QueryParam("link")
|
|
||||||
if link == "" {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "link should not be empty")
|
|
||||||
}
|
|
||||||
if settings.Get().EnableDebug {
|
|
||||||
fmt.Println("Play:", c.QueryParams()) // mute log flood on play
|
|
||||||
}
|
|
||||||
qsave := c.QueryParam("save")
|
|
||||||
qpreload := c.QueryParam("preload")
|
|
||||||
qfile := c.QueryParam("file")
|
|
||||||
qstat := c.QueryParam("stat")
|
|
||||||
mm3u := c.QueryParam("m3u")
|
|
||||||
|
|
||||||
preload := int64(0)
|
|
||||||
stat := strings.ToLower(qstat) == "true"
|
|
||||||
|
|
||||||
if qpreload != "" {
|
|
||||||
preload, _ = strconv.ParseInt(qpreload, 10, 64)
|
|
||||||
if preload > 0 {
|
|
||||||
preload *= 1024 * 1024
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
magnet, infoBytes, err := helpers.GetMagnet(link)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Error get magnet:", link, err)
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
tor := bts.GetTorrent(magnet.InfoHash)
|
|
||||||
if tor == nil {
|
|
||||||
tor, err = bts.AddTorrent(*magnet, infoBytes, nil)
|
|
||||||
if err != nil {
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if stat {
|
|
||||||
return c.JSON(http.StatusOK, getTorPlayState(tor))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !tor.WaitInfo() {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, "torrent closed befor get info")
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.ToLower(qsave) == "true" {
|
|
||||||
if t, err := settings.LoadTorrentDB(magnet.InfoHash.HexString()); t == nil && err == nil {
|
|
||||||
torrDb := toTorrentDB(tor)
|
|
||||||
if torrDb != nil {
|
|
||||||
torrDb.InfoBytes = infoBytes
|
|
||||||
settings.SaveTorrentDB(torrDb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.ToLower(mm3u) == "true" {
|
|
||||||
mt := tor.Torrent.Metainfo()
|
|
||||||
m3u := helpers.MakeM3UPlayList(tor.Stats(), mt.Magnet(tor.Name(), tor.Hash()).String(), c.Scheme()+"://"+c.Request().Host)
|
|
||||||
c.Response().Header().Set("Content-Type", "audio/x-mpegurl")
|
|
||||||
c.Response().Header().Set("Connection", "close")
|
|
||||||
name := utils.CleanFName(tor.Name()) + ".m3u"
|
|
||||||
c.Response().Header().Set("ETag", httptoo.EncodeQuotedString(fmt.Sprintf("%s/%s", tor.Hash().HexString(), name)))
|
|
||||||
c.Response().Header().Set("Content-Disposition", `attachment; filename="`+name+`"`)
|
|
||||||
http.ServeContent(c.Response(), c.Request(), name, time.Now(), bytes.NewReader([]byte(m3u)))
|
|
||||||
return c.NoContent(http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
files := helpers.GetPlayableFiles(tor.Stats())
|
|
||||||
|
|
||||||
if len(files) == 1 {
|
|
||||||
file := helpers.FindFile(files[0].Id, tor)
|
|
||||||
if file == nil {
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprint("File", files[0], "not found in torrent", tor.Name()))
|
|
||||||
}
|
|
||||||
|
|
||||||
return bts.Play(tor, file, preload, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
if qfile == "" && len(files) > 1 {
|
|
||||||
return c.JSON(http.StatusOK, getTorPlayState(tor))
|
|
||||||
}
|
|
||||||
|
|
||||||
fileInd, _ := strconv.Atoi(qfile)
|
|
||||||
file := helpers.FindFile(fileInd, tor)
|
|
||||||
if file == nil {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprint("File index ", fileInd, " not found in torrent ", tor.Name()))
|
|
||||||
}
|
|
||||||
return bts.Play(tor, file, preload, c)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"server/torr/state"
|
"server/torr/state"
|
||||||
"server/web/api/utils"
|
"server/web/api/utils"
|
||||||
|
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -56,6 +55,11 @@ func torrents(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addTorrent(req torrReqJS, c *gin.Context) {
|
func addTorrent(req torrReqJS, c *gin.Context) {
|
||||||
|
if req.Link == "" {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, errors.New("link is empty"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
log.TLogln("add torrent", req.Link)
|
log.TLogln("add torrent", req.Link)
|
||||||
torrSpec, err := utils.ParseLink(req.Link)
|
torrSpec, err := utils.ParseLink(req.Link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -64,44 +68,30 @@ func addTorrent(req torrReqJS, c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
torr, err := torr.NewTorrent(torrSpec, bts)
|
tor, err := torr.AddTorrent(torrSpec, req.Title, req.Poster)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.TLogln("error add torrent:", err)
|
log.TLogln("error add torrent:", err)
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !torr.GotInfo() {
|
|
||||||
log.TLogln("error add torrent:", "timeout connection torrent")
|
|
||||||
c.AbortWithError(http.StatusNotFound, errors.New("timeout connection torrent"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
torr.Title = req.Title
|
|
||||||
torr.Poster = req.Poster
|
|
||||||
|
|
||||||
if torr.Title == "" {
|
|
||||||
torr.Title = torr.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.SaveToDB {
|
if req.SaveToDB {
|
||||||
log.TLogln("save to db:", torr.Torrent.InfoHash().HexString())
|
torr.SaveTorrentToDB(tor)
|
||||||
utils.AddTorrent(torr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
st := torr.Stats()
|
st := tor.Status()
|
||||||
c.JSON(200, st)
|
c.JSON(200, st)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTorrent(req torrReqJS, c *gin.Context) {
|
func getTorrent(req torrReqJS, c *gin.Context) {
|
||||||
hash := metainfo.NewHashFromHex(req.Hash)
|
if req.Hash == "" {
|
||||||
tor := bts.GetTorrent(hash)
|
c.AbortWithError(http.StatusBadRequest, errors.New("hash is empty"))
|
||||||
if tor == nil {
|
return
|
||||||
tor = utils.GetTorrent(hash)
|
|
||||||
}
|
}
|
||||||
|
tor := torr.GetTorrent(req.Hash)
|
||||||
|
|
||||||
if tor != nil {
|
if tor != nil {
|
||||||
st := tor.Stats()
|
st := tor.Status()
|
||||||
c.JSON(200, st)
|
c.JSON(200, st)
|
||||||
} else {
|
} else {
|
||||||
c.Status(http.StatusNotFound)
|
c.Status(http.StatusNotFound)
|
||||||
@@ -109,44 +99,28 @@ func getTorrent(req torrReqJS, c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func remTorrent(req torrReqJS, c *gin.Context) {
|
func remTorrent(req torrReqJS, c *gin.Context) {
|
||||||
hash := metainfo.NewHashFromHex(req.Hash)
|
if req.Hash == "" {
|
||||||
bts.RemoveTorrent(hash)
|
c.AbortWithError(http.StatusBadRequest, errors.New("hash is empty"))
|
||||||
utils.RemTorrent(hash)
|
return
|
||||||
|
}
|
||||||
|
torr.RemTorrent(req.Hash)
|
||||||
c.Status(200)
|
c.Status(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listTorrent(req torrReqJS, c *gin.Context) {
|
func listTorrent(req torrReqJS, c *gin.Context) {
|
||||||
stats := listTorrents()
|
list := torr.ListTorrent()
|
||||||
|
var stats []*state.TorrentStatus
|
||||||
|
for _, tr := range list {
|
||||||
|
stats = append(stats, tr.Status())
|
||||||
|
}
|
||||||
c.JSON(200, stats)
|
c.JSON(200, stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
func listTorrents() []*state.TorrentStats {
|
|
||||||
btlist := bts.ListTorrents()
|
|
||||||
dblist := utils.ListTorrents()
|
|
||||||
var stats []*state.TorrentStats
|
|
||||||
for _, tr := range btlist {
|
|
||||||
stats = append(stats, tr.Stats())
|
|
||||||
}
|
|
||||||
|
|
||||||
mainloop:
|
|
||||||
for _, db := range dblist {
|
|
||||||
for _, tr := range btlist {
|
|
||||||
if tr.Hash() == db.Hash() {
|
|
||||||
continue mainloop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stats = append(stats, db.Stats())
|
|
||||||
}
|
|
||||||
return stats
|
|
||||||
}
|
|
||||||
|
|
||||||
func dropTorrent(req torrReqJS, c *gin.Context) {
|
func dropTorrent(req torrReqJS, c *gin.Context) {
|
||||||
if req.Hash == "" {
|
if req.Hash == "" {
|
||||||
c.AbortWithError(http.StatusBadRequest, errors.New("hash is empty"))
|
c.AbortWithError(http.StatusBadRequest, errors.New("hash is empty"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
hash := metainfo.NewHashFromHex(req.Hash)
|
torr.DropTorrent(req.Hash)
|
||||||
|
|
||||||
bts.RemoveTorrent(hash)
|
|
||||||
c.Status(200)
|
c.Status(200)
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/server/web/api/upload.go
Normal file
51
src/server/web/api/upload.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"server/log"
|
||||||
|
"server/torr"
|
||||||
|
"server/torr/state"
|
||||||
|
"server/web/api/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func torrentUpload(c *gin.Context) {
|
||||||
|
form, err := c.MultipartForm()
|
||||||
|
if err != nil {
|
||||||
|
c.AbortWithError(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer form.RemoveAll()
|
||||||
|
|
||||||
|
save := len(form.Value["save"]) > 0
|
||||||
|
var retList []*state.TorrentStatus
|
||||||
|
|
||||||
|
for name, file := range form.File {
|
||||||
|
log.TLogln("add torrent file", name)
|
||||||
|
|
||||||
|
torrFile, err := file[0].Open()
|
||||||
|
if err != nil {
|
||||||
|
log.TLogln("error upload torrent:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
defer torrFile.Close()
|
||||||
|
|
||||||
|
spec, err := utils.ParseFile(torrFile)
|
||||||
|
if err != nil {
|
||||||
|
log.TLogln("error upload torrent:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
tor, err := torr.AddTorrent(spec, "", "")
|
||||||
|
if err != nil {
|
||||||
|
log.TLogln("error upload torrent:", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if save {
|
||||||
|
torr.SaveTorrentToDB(tor)
|
||||||
|
}
|
||||||
|
retList = append(retList, tor.Status())
|
||||||
|
}
|
||||||
|
c.JSON(200, retList)
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -13,6 +14,25 @@ import (
|
|||||||
"github.com/anacrolix/torrent/metainfo"
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func ParseFile(file multipart.File) (*torrent.TorrentSpec, error) {
|
||||||
|
minfo, err := metainfo.Load(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
info, err := minfo.UnmarshalInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mag := minfo.Magnet(info.Name, minfo.HashInfoBytes())
|
||||||
|
return &torrent.TorrentSpec{
|
||||||
|
InfoBytes: minfo.InfoBytes,
|
||||||
|
Trackers: [][]string{mag.Trackers},
|
||||||
|
DisplayName: info.Name,
|
||||||
|
InfoHash: minfo.HashInfoBytes(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ParseLink(link string) (*torrent.TorrentSpec, error) {
|
func ParseLink(link string) (*torrent.TorrentSpec, error) {
|
||||||
urlLink, err := url.Parse(link)
|
urlLink, err := url.Parse(link)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -40,9 +60,14 @@ func fromMagnet(link string) (*torrent.TorrentSpec, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var trackers [][]string
|
||||||
|
if len(mag.Trackers) > 0 {
|
||||||
|
trackers = [][]string{mag.Trackers}
|
||||||
|
}
|
||||||
|
|
||||||
return &torrent.TorrentSpec{
|
return &torrent.TorrentSpec{
|
||||||
InfoBytes: nil,
|
InfoBytes: nil,
|
||||||
Trackers: [][]string{mag.Trackers},
|
Trackers: trackers,
|
||||||
DisplayName: mag.DisplayName,
|
DisplayName: mag.DisplayName,
|
||||||
InfoHash: mag.InfoHash,
|
InfoHash: mag.InfoHash,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import (
|
|||||||
sets "server/settings"
|
sets "server/settings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
file index starts from 1
|
||||||
|
*/
|
||||||
|
|
||||||
// Action: set, rem, list
|
// Action: set, rem, list
|
||||||
type viewedReqJS struct {
|
type viewedReqJS struct {
|
||||||
requestI
|
requestI
|
||||||
|
|||||||
Reference in New Issue
Block a user