Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve Scheduler, Auth and Cache (v.3.5) #319

Merged
merged 14 commits into from
May 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 45 additions & 43 deletions .github/workflows/pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ on:
- "scripts/**"
- "**.sh"
- "docs/**"
workflow_dispatch:

concurrency:
group: ${{ github.ref }}-pre-release
Expand All @@ -42,58 +43,59 @@ jobs:
wget -q --show-progress https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
unzip -qq android-ndk-r26b-linux.zip
echo "$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH

- name: Build Executables 🗄️ 🔃
run: |
mkdir -p bin
allowed_archs="amd64 arm arm64 386"
for var in $(go tool dist list); do
# skip disallowed archs
if [[ ! $allowed_archs =~ "$(cut -d '/' -f 2 <<<$var)" ]]; then
echo "Skipping: $var"
continue
fi
# skip arm for windows
if [[ "$(cut -d '/' -f 1 <<<$var)" == "windows" && "$(cut -d '/' -f 2 <<<$var)" == "arm" ]]; then
echo "Skipping: $var (windows/arm)"
continue
fi
# skip 386 for android
if [[ "$(cut -d '/' -f 1 <<<$var)" == "android" && "$(cut -d '/' -f 2 <<<$var)" == "386" ]]; then
echo "Skipping: $var (android/386)"
continue
fi
case "$(cut -d '/' -f 1 <<<$var)" in
"windows")
echo "Building $var"
CGO_ENABLED=0 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var).exe" -trimpath -ldflags="-s -w" .
;;
# skip disallowed archs
if [[ ! $allowed_archs =~ "$(cut -d '/' -f 2 <<<$var)" ]]; then
echo "Skipping: $var"
continue
fi
# skip arm for windows
if [[ "$(cut -d '/' -f 1 <<<$var)" == "windows" && "$(cut -d '/' -f 2 <<<$var)" == "arm" ]]; then
echo "Skipping: $var (windows/arm)"
continue
fi

file_name="jiotv_go-$(cut -d '/' -f 1 <<< $var)-$(cut -d '/' -f 2 <<< $var)"
case "$(cut -d '/' -f 1 <<< $var)" in
"windows")
echo "Building $var"
CGO_ENABLED=0 GOOS="$(cut -d '/' -f 1 <<< $var)" GOARCH="$(cut -d '/' -f 2 <<< $var)" go build -o bin/"$file_name.exe" -trimpath -ldflags="-s -w" . &
;;
"linux" | "darwin")
echo "Building $var"
CGO_ENABLED=0 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
echo "Building $var"
CGO_ENABLED=0 GOOS="$(cut -d '/' -f 1 <<< $var)" GOARCH="$(cut -d '/' -f 2 <<< $var)" go build -o bin/"$file_name" -trimpath -ldflags="-s -w" . &
;;
"android")
echo "Building $var"
case "$(cut -d '/' -f 2 <<<$var)" in
"arm")
CGO_ENABLED=1 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" CC="armv7a-linux-androideabi28-clang" CXX="armv7a-linux-androideabi28-clang++" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
"arm64")
CGO_ENABLED=1 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" CC="aarch64-linux-android32-clang" CXX="aarch64-linux-android32-clang++" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
"amd64")
CGO_ENABLED=1 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" CC="x86_64-linux-android32-clang" CXX="x86_64-linux-android32-clang++" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
*)
echo "Skipping: $var"
;;
esac
;;
echo "Building $var"
case "$(cut -d '/' -f 2 <<<$var)" in
"arm")
CGO_ENABLED=1 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" CC="armv7a-linux-androideabi28-clang" CXX="armv7a-linux-androideabi28-clang++" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
"arm64")
CGO_ENABLED=1 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" CC="aarch64-linux-android32-clang" CXX="aarch64-linux-android32-clang++" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
"amd64")
CGO_ENABLED=1 GOOS="$(cut -d '/' -f 1 <<<$var)" GOARCH="$(cut -d '/' -f 2 <<<$var)" CC="x86_64-linux-android32-clang" CXX="x86_64-linux-android32-clang++" go build -o bin/"jiotv_go-$(cut -d '/' -f 1 <<<$var)-$(cut -d '/' -f 2 <<<$var)" -trimpath -ldflags="-s -w" .
;;
*)
echo "Skipping: $var"
;;
esac
;;
*)
echo "Skipping: $var"
;;
esac
echo "Skipping: $var"
;;
esac
done

# Wait for all background jobs to finish
wait

- name: Delete previous release 🗑️
run: |
tag=$(git describe --tags --match "${{ github.ref_name }}.[0-9]*.[0-9]*.[0-9]*" --abbrev=0)
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM golang:1.21-alpine AS builder
FROM golang:1.22-alpine AS builder

# Set the working directory inside the container
WORKDIR /app
Expand Down
7 changes: 6 additions & 1 deletion cmd/jiotv_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"github.com/rabilrbl/jiotv_go/v3/internal/config"
"github.com/rabilrbl/jiotv_go/v3/internal/handlers"
"github.com/rabilrbl/jiotv_go/v3/internal/middleware"
"github.com/rabilrbl/jiotv_go/v3/pkg/store"
"github.com/rabilrbl/jiotv_go/v3/pkg/epg"
"github.com/rabilrbl/jiotv_go/v3/pkg/scheduler"
"github.com/rabilrbl/jiotv_go/v3/pkg/secureurl"
"github.com/rabilrbl/jiotv_go/v3/pkg/store"
"github.com/rabilrbl/jiotv_go/v3/pkg/utils"
"github.com/rabilrbl/jiotv_go/v3/web"

Expand Down Expand Up @@ -49,6 +50,10 @@ func JioTVServer(host, port, configPath string, prefork bool) error {
go epg.Init()
}

// Start Scheduler
scheduler.Init()
defer scheduler.Stop()

engine := html.NewFileSystem(http.FS(web.GetViewFiles()), ".html")
if config.Cfg.Debug {
engine.Reload(true)
Expand Down
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/rabilrbl/jiotv_go/v3

go 1.21
go 1.22

require (
github.com/BurntSushi/toml v1.4.0
Expand All @@ -15,6 +15,7 @@ require (
github.com/gofiber/utils v1.1.0 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
golang.org/x/net v0.23.0 // indirect
Expand All @@ -29,6 +30,7 @@ require (
github.com/gofiber/template/html/v2 v2.1.1
github.com/google/uuid v1.5.0 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/madflojo/tasks v1.2.0
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/madflojo/tasks v1.2.0 h1:wYVgHx293eFFN2xtfsgNQ8T4LUPZEdnGH5jvLn3B7kg=
github.com/madflojo/tasks v1.2.0/go.mod h1:BKSfcHnUSlQMA5wXdaxgthhKc75GfVIivEywn2YWqt0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
Expand All @@ -39,6 +41,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/schollz/progressbar/v3 v3.14.3 h1:oOuWW19ka12wxYU1XblR4n16wF/2Y1dBLMarMo6p4xU=
Expand Down
41 changes: 36 additions & 5 deletions internal/handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ import (
"time"

"github.com/gofiber/fiber/v2"
"github.com/rabilrbl/jiotv_go/v3/pkg/scheduler"
"github.com/rabilrbl/jiotv_go/v3/pkg/television"
"github.com/rabilrbl/jiotv_go/v3/pkg/utils"
"github.com/valyala/fasthttp"
)

const (
REFRESH_TOKEN_TASK_ID = "jiotv_refresh_token"
REFRESH_SSOTOKEN_TASK_ID = "jiotv_refresh_sso_token"
)

// LoginSendOTPHandler sends OTP for login
func LoginSendOTPHandler(c *fiber.Ctx) error {
// get mobile number from post request
Expand Down Expand Up @@ -243,35 +249,60 @@ func LoginRefreshSSOToken() error {
// Update tokenData
if response.SSOToken != "" {
tokenData.SSOToken = response.SSOToken
tokenData.LastTokenRefreshTime = strconv.FormatInt(time.Now().Unix(), 10)
tokenData.LastSSOTokenRefreshTime = strconv.FormatInt(time.Now().Unix(), 10)
err := utils.WriteJIOTVCredentials(tokenData)
if err != nil {
utils.Log.Fatalln(err)
return err
}
TV = television.New(tokenData)
go RefreshTokenIfExpired(tokenData)
go RefreshSSOTokenIfExpired(tokenData)
return nil
} else {
return fmt.Errorf("SSOToken not found in response")
}
}

// RefreshTokenIfExpired Function is used to handle AccessToken refresh
func RefreshTokenIfExpired(credentials *utils.JIOTV_CREDENTIALS) {
func RefreshTokenIfExpired(credentials *utils.JIOTV_CREDENTIALS) error {
utils.Log.Println("Checking if AccessToken is expired...")
lastTokenRefreshTime, err := strconv.ParseInt(credentials.LastTokenRefreshTime, 10, 64)
if err != nil {
utils.Log.Fatal(err)
return err
}
lastTokenRefreshTimeUnix := time.Unix(lastTokenRefreshTime, 0)
thresholdTime := lastTokenRefreshTimeUnix.Add(1*time.Hour + 50*time.Minute)

if thresholdTime.Before(time.Now()) {
LoginRefreshAccessToken()
LoginRefreshSSOToken()
} else {
utils.Log.Println("Refreshing AccessToken after", time.Until(thresholdTime).Truncate(time.Second))
go utils.ScheduleFunctionCall(func() { RefreshTokenIfExpired(credentials) }, thresholdTime)
go scheduler.Add(REFRESH_TOKEN_TASK_ID, time.Until(thresholdTime), func() error {
return RefreshTokenIfExpired(credentials)
})
}
return nil
}

// RefreshSSOTokenIfExpired Function is used to handle SSOToken refresh
func RefreshSSOTokenIfExpired(credentials *utils.JIOTV_CREDENTIALS) error {
utils.Log.Println("Checking if SSOToken is expired...")
lastTokenRefreshTime, err := strconv.ParseInt(credentials.LastSSOTokenRefreshTime, 10, 64)
if err != nil {
utils.Log.Fatal(err)
return err
}
lastTokenRefreshTimeUnix := time.Unix(lastTokenRefreshTime, 0)
thresholdTime := lastTokenRefreshTimeUnix.Add(24 * time.Hour)

if thresholdTime.Before(time.Now()) {
LoginRefreshSSOToken()
} else {
utils.Log.Println("Refreshing SSOToken after", time.Until(thresholdTime).Truncate(time.Second))
go scheduler.Add(REFRESH_SSOTOKEN_TASK_ID, time.Until(thresholdTime), func() error {
return RefreshSSOTokenIfExpired(credentials)
})
}
return nil
}
29 changes: 16 additions & 13 deletions internal/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ func Init() {
// Check validity of credentials
go RefreshTokenIfExpired(credentials)
}
// If SsoToken is present, check for its validity and schedule a refresh if required
if credentials.SSOToken != "" {
go RefreshSSOTokenIfExpired(credentials)
}
// Initialize TV object with credentials
TV = television.New(credentials)
}
Expand Down Expand Up @@ -134,11 +138,9 @@ func LiveHandler(c *fiber.Ctx) error {
liveResult, err := TV.Live(id)
if err != nil {
utils.Log.Println(err)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"message": err,
})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"message": err,
})
}
if id[:2] == "sl" {
return sonyLivRedirect(c, liveResult)
Expand All @@ -162,15 +164,13 @@ func LiveQualityHandler(c *fiber.Ctx) error {
// remove suffix .m3u8 if exists
id = strings.Replace(id, ".m3u8", "", 1)
liveResult, err := TV.Live(id)
Bitrates := liveResult.Bitrates
if err != nil {
utils.Log.Println(err)
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"message": err,
})
}
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"message": err,
})
}
Bitrates := liveResult.Bitrates
if id[:2] == "sl" {
return sonyLivRedirect(c, liveResult)
}
Expand Down Expand Up @@ -275,7 +275,7 @@ func RenderHandler(c *fiber.Ctx) error {
utils.Log.Println("Error rendering M3U8 file")
utils.Log.Println(string(renderResult))
}

c.Response().Header.Set("Cache-Control", "public, must-revalidate, max-age=3")
return c.Status(statusCode).Send(renderResult)
}

Expand All @@ -298,7 +298,6 @@ func SLHandler(c *fiber.Ctx) error {

c.Response().Header.Del(fiber.HeaderServer)
c.Response().Header.Add("Access-Control-Allow-Origin", "*")

return nil
}

Expand Down Expand Up @@ -396,6 +395,7 @@ func ChannelsHandler(c *fiber.Ctx) error {
// Set the Content-Disposition header for file download
c.Set("Content-Disposition", "attachment; filename=jiotv_playlist.m3u")
c.Set("Content-Type", "application/vnd.apple.mpegurl") // Set the video M3U MIME type
c.Response().Header.Set("Cache-Control", "public, max-age=3600")
return c.SendString(m3uContent)
}

Expand All @@ -418,6 +418,7 @@ func PlayHandler(c *fiber.Ctx) error {
} else {
player_url = "/player/" + id + "?q=" + quality
}
c.Response().Header.Set("Cache-Control", "public, max-age=3600")
return c.Render("views/play", fiber.Map{
"Title": Title,
"player_url": player_url,
Expand All @@ -434,6 +435,7 @@ func PlayerHandler(c *fiber.Ctx) error {
} else {
play_url = "/live/" + id + ".m3u8"
}
c.Response().Header.Set("Cache-Control", "public, max-age=3600")
return c.Render("views/flow_player", fiber.Map{
"play_url": play_url,
})
Expand All @@ -449,6 +451,7 @@ func ClapprHandler(c *fiber.Ctx) error {
} else {
play_url = "/live/" + id + ".m3u8"
}
c.Response().Header.Set("Cache-Control", "public, max-age=3600")
return c.Render("views/clappr", fiber.Map{
"play_url": play_url,
})
Expand Down
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func main() {
Name: "JioTV Go",
Usage: "Stream JioTV on any device",
HelpName: "jiotv_go",
Version: "v3.4.8",
Version: "v3.4.8",
Copyright: "© JioTV Go by Mohammed Rabil (https://github.com/rabilrbl/jiotv_go)",
Compiled: time.Now(),
Suggest: true,
Expand Down
Loading
Loading