Files
TorrServerJellyfin/server/web/msx/msx.go
2021-09-26 14:38:37 +03:00

263 lines
6.1 KiB
Go

package msx
import (
"fmt"
"net/url"
"path/filepath"
"strings"
sets "server/settings"
"server/torr"
"server/torr/state"
"server/utils"
"server/version"
"github.com/gin-gonic/gin"
)
type msxMenu struct {
Logo string `json:"logo,omitempty"`
Reuse bool `json:"reuse"`
Cache bool `json:"cache"`
Restore bool `json:"restore"`
Reference string `json:"reference,omitempty"`
Menu []msxMenuItem `json:"menu"`
}
type msxMenuItem struct {
Icon string `json:"icon,omitempty"`
Label string `json:"label,omitempty"`
Data msxData `json:"data,omitempty"`
}
type msxTemplate struct {
Type string `json:"type,omitempty"`
Layout string `json:"layout,omitempty"`
Color string `json:"color,omitempty"`
Icon string `json:"icon,omitempty"`
IconSize string `json:"iconSize,omitempty"`
BadgeColor string `json:"badgeColor,omitempty"`
TagColor string `json:"tagColor,omitempty"`
Properties gin.H `json:"properties,omitempty"`
}
type msxData struct {
Type string `json:"type,omitempty"`
Headline string `json:"headline,omitempty"`
Action string `json:"action,omitempty"`
Template msxTemplate `json:"template,omitempty"`
Items []msxItem `json:"items,omitempty"`
Pages []msxPage `json:"pages,omitempty"`
}
type msxItem struct {
Title string `json:"title,omitempty"`
Label string `json:"label,omitempty"`
PlayerLabel string `json:"playerLabel,omitempty"`
Action string `json:"action,omitempty"`
Image string `json:"image,omitempty"`
Icon string `json:"icon,omitempty"`
Badge string `json:"badge,omitempty"`
Tag string `json:"tag,omitempty"`
Data gin.H `json:"data,omitempty"`
}
type msxPage struct {
Items []gin.H `json:"items,omitempty"`
}
const ICON_OPTIONS = "tune"
func msxStart(c *gin.Context) {
c.JSON(200, gin.H{
"name": "TorrServer",
"version": version.Version,
"parameter": "menu:{PREFIX}{SERVER}/msx/torrents",
})
}
// /msx/torrents
func msxTorrents(c *gin.Context) {
torrs := torr.ListTorrent()
host := utils.GetScheme(c) + "://" + c.Request.Host
logo := host + "/apple-touch-icon.png"
list := make([]msxItem, len(torrs))
for i, tor := range torrs {
item := msxItem{
Title: tor.Title,
Image: tor.Poster,
Action: "content:" + host + "/msx/playlist/" + url.PathEscape(tor.Title) +
"?hash=" + tor.TorrentSpec.InfoHash.HexString() + "&platform={PLATFORM}",
}
list[i] = item
}
c.JSON(200, msxMenu{
Logo: logo,
Cache: false,
Reuse: false,
Restore: false,
Reference: host + "/msx/torrents",
Menu: []msxMenuItem{
// Main page
{
Icon: "list",
Label: "Torrents",
Data: msxData{
Type: "pages",
Template: msxTemplate{
Type: "separate",
Layout: "0,0,2,4",
Icon: "msx-white-soft:movie",
Color: "msx-glass",
},
Items: list,
},
// About
}, {
Icon: "info",
Label: "About",
Data: msxData{
Pages: []msxPage{
{
Items: []gin.H{
{
"type": "default",
"headline": "TorrServer " + version.Version,
"text": "https://github.com/YouROK/TorrServer",
"image": logo,
"imageFiller": "height-left",
"imageWidth": 2,
"layout": "0,0,8,2",
"color": "msx-gray-soft",
},
},
},
},
},
},
},
})
}
// /msx/playlist?hash=...
func msxPlaylist(c *gin.Context) {
hash, _ := c.GetQuery("hash")
if hash == "" {
c.JSON(200, msxData{
Action: "error:Item not found",
})
return
}
platform, _ := c.GetQuery("platform")
tor := torr.GetTorrent(hash)
if tor == nil {
c.JSON(200, msxData{
Action: "error:Item not found",
})
return
}
if tor.Stat == state.TorrentInDB {
tor = torr.LoadTorrent(tor)
if tor == nil {
c.JSON(200, msxData{
Action: "error:Error while getting torrent info",
})
return
}
}
host := utils.GetScheme(c) + "://" + c.Request.Host
status := tor.Status()
viewed := sets.ListViewed(hash)
var list []msxItem
contentAction := ""
for _, f := range status.FileStats {
mime := utils.GetMimeType(f.Path)
action := mime[0 : len(mime)-2]
if action == "*" {
continue
}
name := filepath.Base(f.Path)
uri := host + "/stream/" + url.PathEscape(name) + "?link=" + hash + "&index=" + fmt.Sprint(f.Id) + "&play"
item := msxItem{
Label: name,
PlayerLabel: strings.TrimSuffix(name, filepath.Ext(name)),
Action: action + ":" + uri,
}
if platform == "android" || platform == "firetv" {
item.Action = "system:tvx:launch"
item.Data = gin.H{
"id": hash + "-" + fmt.Sprint(f.Id),
"uri": uri,
"type": mime,
}
} else if platform == "tizen" {
contentAction = "content:request:interaction:init@" + host + "/msx/tizen.html"
} else if platform == "netcast" {
contentAction = "system:netcast:menu"
} else if platform == "ios" || platform == "mac" {
// TODO - for iOS and Mac the application must be defined in scheme but we don't know what user has installed
item.Action = "system:tvx:launch:vlc://" + uri
} else {
item.Action = "video:plugin:" + host + "/msx/html5x.html?url= " + url.QueryEscape(uri)
contentAction = "panel:request:player:options"
}
if isViewed(viewed, f.Id) {
item.Tag = " "
}
if action == "audio" {
item.Icon = "msx-white-soft:music-note"
}
list = append(list, item)
}
if len(list) == 0 {
c.JSON(200, msxData{
Action: "error:No supported content found",
})
return
}
res := msxData{
Headline: tor.Title,
Type: "list",
Template: msxTemplate{
Type: "control",
Layout: "0,2,12,1",
Color: "msx-glass",
Icon: "msx-white-soft:movie",
IconSize: "medium",
BadgeColor: "msx-yellow",
TagColor: "msx-yellow",
},
Items: list,
}
if contentAction != "" {
res.Template.Properties = gin.H{
"button:content:icon": ICON_OPTIONS,
"button:content:action": contentAction,
}
}
c.JSON(200, res)
}
func isViewed(viewed []*sets.Viewed, id int) bool {
for _, v := range viewed {
if v.FileIndex == id {
return true
}
}
return false
}