diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 32922a53..3b0fb3cb 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ { "name": "Go", // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/go:1-1.22-bullseye", + "image": "mcr.microsoft.com/devcontainers/go:1-1.23-bullseye", "features": { "ghcr.io/devcontainers/features/common-utils:2": { "installZsh": true, diff --git a/go.mod b/go.mod index 183da0cb..c7f4789c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/BurntSushi/toml v1.4.0 github.com/ilyakaznacheev/cleanenv v1.5.0 github.com/urfave/cli/v2 v2.27.4 - golang.org/x/term v0.23.0 + golang.org/x/term v0.24.0 ) require ( @@ -39,6 +39,6 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/sys v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index a8dd727b..a8987b10 100644 --- a/go.sum +++ b/go.sum @@ -66,11 +66,11 @@ golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 1885fedd..4ff5a6cd 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -131,7 +131,7 @@ func LoginRefreshAccessToken() error { // Prepare the request body requestBody := map[string]string{ "appName": "RJIL_JioTV", - "deviceId": "6fcadeb7b4b10d77", + "deviceId": utils.GetDeviceID(), "refreshToken": tokenData.RefreshToken, } @@ -218,7 +218,7 @@ func LoginRefreshSSOToken() error { req.Header.Set("User-Agent", "okhttp/4.2.2") req.Header.Set("ssoToken", tokenData.SSOToken) req.Header.Set("uniqueid", tokenData.UniqueID) - req.Header.Set("deviceid", "6fcadeb7b4b10d77") + req.Header.Set("deviceid", utils.GetDeviceID()) // Send the request resp := fasthttp.AcquireResponse() diff --git a/internal/handlers/drm.go b/internal/handlers/drm.go index efba9a01..64e447ef 100644 --- a/internal/handlers/drm.go +++ b/internal/handlers/drm.go @@ -132,7 +132,7 @@ func DRMKeyHandler(c *fiber.Ctx) error { c.Request().Header.Set("devicetype", "phone") c.Request().Header.Set("Accept-Encoding", "gzip, deflate") c.Request().Header.Set("osVersion", "13") - c.Request().Header.Set("deviceId", "b6985e8cf2401d35") + c.Request().Header.Set("deviceId", utils.GetDeviceID()) c.Request().Header.Set("Content-Type", "application/octet-stream") // Delete User-Agent header from the request diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 8793214c..95dbee27 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -48,6 +48,8 @@ func Init() { if DisableTSHandler { utils.Log.Println("TS Handler disabled!. All TS video requests will be served directly from JioTV servers.") } + // Generate a new device ID if not present + utils.GetDeviceID() // Get credentials from file credentials, err := utils.GetJIOTVCredentials() // Initialize TV object with nil credentials diff --git a/pkg/epg/epg.go b/pkg/epg/epg.go index 538d6b57..b982aafd 100644 --- a/pkg/epg/epg.go +++ b/pkg/epg/epg.go @@ -23,6 +23,8 @@ const ( CHANNEL_URL = "https://jiotv.data.cdn.jio.com/apis/v3.0/getMobileChannelList/get/?os=android&devicetype=phone&usertype=tvYR7NSNn7rymo3F" // URL for fetching EPG data for individual channels from JioTV API EPG_URL = "https://jiotv.data.cdn.jio.com/apis/v1.3/getepg/get/?offset=%d&channel_id=%d" + // EPG_POSTER_URL + EPG_POSTER_URL = "https://jiotv.catchup.cdn.jio.com/dare_images/shows" // EPG_TASK_ID is the ID of the EPG generation task EPG_TASK_ID = "jiotv_epg" ) @@ -81,7 +83,7 @@ func Init() { // NewProgramme creates a new Programme with the given parameters. func NewProgramme(channelID int, start, stop, title, desc, category, iconSrc string) Programme { - iconURL := fmt.Sprintf("/jtvposter/%s", iconSrc) + iconURL := fmt.Sprintf("%s/%s", EPG_POSTER_URL, iconSrc) return Programme{ Channel: fmt.Sprint(channelID), Start: start, @@ -121,7 +123,7 @@ func genXML() ([]byte, error) { resp := fasthttp.AcquireResponse() - for offset := -1; offset < 2; offset++ { + for offset := 0; offset < 2; offset++ { reqUrl := fmt.Sprintf(EPG_URL, offset, channel.ID) req.SetRequestURI(reqUrl) diff --git a/pkg/store/store.go b/pkg/store/store.go index bcaf4127..d3082248 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -29,7 +29,8 @@ var KVS *TomlStore // Init initializes the TOML file, creates if not exist, otherwise reads and decodes to struct. func Init() error { KVS = &TomlStore{} - filename := filepath.Join(GetPathPrefix(), "store_v2.toml") + // store_vX.toml, where X is changed whenever new version requires re-login + filename := filepath.Join(GetPathPrefix(), "store_v4.toml") KVS.mu.Lock() defer KVS.mu.Unlock() diff --git a/pkg/television/television.go b/pkg/television/television.go index ede5eed6..79e2b502 100644 --- a/pkg/television/television.go +++ b/pkg/television/television.go @@ -35,7 +35,7 @@ func New(credentials *utils.JIOTV_CREDENTIALS) *Television { "channel_id": "", "crmid": credentials.CRM, "userId": credentials.CRM, - "deviceId": "e4286d7b481d69b8", + "deviceId": utils.GetDeviceID(), "devicetype": "phone", "isott": "false", "languageId": "6", diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 0a464847..e303a1f6 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,8 +1,10 @@ package utils import ( + "crypto/rand" "crypto/tls" "encoding/base64" + "encoding/hex" "encoding/json" "fmt" "log" @@ -124,7 +126,7 @@ func LoginVerifyOTP(number, otp string) (map[string]string, error) { Platform: LoginPayloadDeviceInfoInfoPlatform{ Name: "SM-G930F", }, - AndroidID: "6fcadeb7b4b10d77", + AndroidID: GetDeviceID(), }, }, } @@ -248,7 +250,7 @@ func Login(username, password string) (map[string]string, error) { Name: "vbox86p", Version: "8.0.0", }, - AndroidID: "6fcadeb7b4b10d77", + AndroidID: GetDeviceID(), }, }, } @@ -325,6 +327,28 @@ func GetPathPrefix() string { return store.GetPathPrefix() } +// GetDeviceID returns the device ID +func GetDeviceID() string { + deviceID, err := store.Get("deviceId") + if err != nil { + Log.Println(err) + err = GenerateRandomString() + if err != nil { + Log.Println(err) + return "" + } + deviceID, err = store.Get("deviceId") + if deviceID == "" { + Log.Println("Device ID is empty") + return "" + } else if err != nil { + Log.Println(err) + return "" + } + } + return deviceID +} + // GetJIOTVCredentials return credentials from environment variables or credentials file // Important note: If credentials are provided from environment variables, they will be used instead of credentials file func GetJIOTVCredentials() (*JIOTV_CREDENTIALS, error) { @@ -536,3 +560,15 @@ func ContainsString(item string, slice []string) bool { } return false } + +// GenerateRandomString generates a random 16-character hexadecimal string. +func GenerateRandomString() error { + bytes := make([]byte, 8) // 8 bytes will result in a 16-character hex string + if _, err := rand.Read(bytes); err != nil { + return err + } + if _, err := store.Get("deviceId"); err != nil { + store.Set("deviceId", hex.EncodeToString(bytes)) + } + return nil +}