googleplay/delivery.go

150 lines
3.1 KiB
Go

package googleplay
import (
"2a.pages.dev/rosso/protobuf"
"errors"
"io"
"net/http"
"net/url"
"strconv"
)
type File struct {
Package_Name string
Version_Code uint64
}
func (f File) APK(id string) string {
b := []byte(f.Package_Name)
b = append(b, '-')
if id != "" {
b = append(b, id...)
b = append(b, '-')
}
b = strconv.AppendUint(b, f.Version_Code, 10)
b = append(b, ".apk"...)
return string(b)
}
func (f File) OBB(file_type uint64) string {
var b []byte
if file_type >= 1 {
b = append(b, "patch"...)
} else {
b = append(b, "main"...)
}
b = append(b, '.')
b = strconv.AppendUint(b, f.Version_Code, 10)
b = append(b, '.')
b = append(b, f.Package_Name...)
b = append(b, ".obb"...)
return string(b)
}
func (h Header) Delivery(app string, ver uint64) (*Delivery, error) {
req, err := http.NewRequest(
"GET", "https://play-fe.googleapis.com/fdfe/delivery", nil,
)
if err != nil {
return nil, err
}
h.Set_Agent(req.Header)
h.Set_Auth(req.Header) // needed for single APK
h.Set_Device(req.Header)
req.URL.RawQuery = url.Values{
"doc": {app},
"vc": {strconv.FormatUint(ver, 10)},
}.Encode()
res, err := Client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
// ResponseWrapper
response_wrapper, err := protobuf.Unmarshal(body)
if err != nil {
return nil, err
}
// .payload.deliveryResponse
delivery_response := response_wrapper.Get(1).Get(21)
// .status
status, err := delivery_response.Get_Varint(1)
if err != nil {
return nil, err
}
switch status {
case 2:
return nil, errors.New("geo-blocking")
case 3:
return nil, errors.New("purchase required")
case 5:
return nil, errors.New("invalid version")
}
var del Delivery
// .appDeliveryData
del.Message = delivery_response.Get(2)
return &del, nil
}
// .downloadUrl
func (d Delivery) Download_URL() (string, error) {
return d.Get_String(3)
}
func (d Delivery) Split_Data() []Split_Data {
var splits []Split_Data
// .splitDeliveryData
for _, split := range d.Get_Messages(15) {
splits = append(splits, Split_Data{split})
}
return splits
}
// AndroidAppDeliveryData
type Delivery struct {
protobuf.Message
}
func (d Delivery) Additional_File() []App_File_Metadata {
var files []App_File_Metadata
// .additionalFile
for _, file := range d.Get_Messages(4) {
files = append(files, App_File_Metadata{file})
}
return files
}
// SplitDeliveryData
type Split_Data struct {
protobuf.Message
}
// .id
func (s Split_Data) ID() (string, error) {
return s.Get_String(1)
}
// .downloadUrl
func (s Split_Data) Download_URL() (string, error) {
return s.Get_String(5)
}
// AppFileMetadata
type App_File_Metadata struct {
protobuf.Message
}
// .fileType
func (a App_File_Metadata) File_Type() (uint64, error) {
return a.Get_Varint(1)
}
// .downloadUrl
func (a App_File_Metadata) Download_URL() (string, error) {
return a.Get_String(4)
}