From 10d208f0223a65196bda7923828df4f1eeccb239 Mon Sep 17 00:00:00 2001 From: gkiviv Date: Fri, 1 Nov 2024 14:34:54 +0200 Subject: [PATCH] initial commit --- downloader/downloader.go | 178 ++++++++++++++++++++++++++++++++++ downloader/downloader_test.go | 56 +++++++++++ go.mod | 3 + main.go | 18 ++++ 4 files changed, 255 insertions(+) create mode 100644 downloader/downloader.go create mode 100644 downloader/downloader_test.go create mode 100644 go.mod create mode 100644 main.go diff --git a/downloader/downloader.go b/downloader/downloader.go new file mode 100644 index 0000000..2ac2e14 --- /dev/null +++ b/downloader/downloader.go @@ -0,0 +1,178 @@ +package downloader + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "regexp" +) + +type ContentPageData struct { + Data Data `json:"data"` +} + +type Data struct { + MainContent MainContent `json:"mainContent"` + SeasonList SeasonList `json:"seasonList"` +} + +type MainContent struct { + Medias []Media `json:"medias"` + Title string `json:"fancyUrl"` + Season int `json:"season"` + Episode int `json:"episode"` +} + +type SeasonList struct { + Type string `json:"type"` + Seasons []Season `json:"items"` +} + +type Season struct { + Name string `json:"name"` + Contents []Content `json:"contents"` +} + +type Content struct { + Url string `json:"url"` +} + +type Media struct { + Src Source `json:"src"` + Subtitles []Subtitles `json:"subtitles"` +} + +type Subtitles struct { + Src string `json:"src"` + FileName string `json:"filename"` + SrcLang string `json:"srclang"` +} + +type Source struct { + File string `json:"file"` +} + +func DownloadSingle(url string, filename string, subtitleLang string) { + id := ExtractContentId(url) + data := GetContentPageData(id) + downloadUrl := GetDownloadUrl(data) + dirCreated := false + + if filename == "" { + filename = fmt.Sprintf("%s_%d_%d", data.Data.MainContent.Title, data.Data.MainContent.Season, data.Data.MainContent.Episode) + } + + if subtitleLang != "" { + subtitles := data.Data.MainContent.Medias[0].Subtitles + + if len(subtitles) == 0 { + fmt.Println("No subtitles for this media") + return + } + + fmt.Println("Fetching subtitles") + + for _, subtitle := range subtitles { + if subtitle.SrcLang == subtitleLang { + _ = os.Mkdir(filename, os.ModePerm) // dont care if directory fails to create + subitleFileName := fmt.Sprintf("%s/%s_%s", filename, filename, subtitle.FileName) + downloadFile(subtitle.Src, subitleFileName) + fmt.Println("Subtitles downloaded successfully") + dirCreated = true + break + } + } + } + filepath := fmt.Sprintf("%s.mp4", filename) + + if dirCreated { + filepath = fmt.Sprintf("%s/%s.mp4", filename, filename) + } + + fmt.Printf("Downloading %s to %s\n", url, filename) + downloadFile(downloadUrl, filepath) + fmt.Printf("Finished Downloading %s to %s\n", url, filename) +} + +func DownloadSeason(url string, seasonName string, subtitleLang string) { + id := ExtractContentId(url) + // fmt.Println(id) + data := GetContentPageData(id) + + title := data.Data.MainContent.Title + seasonList := data.Data.SeasonList + if seasonList.Type != "seasonal" { + panic("Invalid seasontype") + } + + for _, season := range seasonList.Seasons { + if season.Name == seasonName { + for _, seasonContent := range season.Contents { + _ = os.Mkdir(title, os.ModePerm) // dont care if directory fails to create + // fileName := fmt.Sprintf("%s/episood_%s", title, strconv.Itoa(i+1)) + DownloadSingle(seasonContent.Url, "", subtitleLang) + } + } + } +} + +func downloadFile(url string, filepath string) { + out, err := os.Create(filepath) + if err != nil { + panic(err) + } + defer out.Close() + + resp, err := http.Get(url) + + if err != nil { + panic(err) + } + + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + panic("Bad status") + } + + _, err = io.Copy(out, resp.Body) + + if err != nil { + panic(err) + } +} + +func GetContentPageData(contentId string) *ContentPageData { + var data ContentPageData + + url := fmt.Sprintf("https://services.err.ee/api/v2/vodContent/getContentPageData?contentId=%s&rootId=3905", contentId) + + resp, err := http.Get(url) + if err != nil { + panic("Invalid url") + } + + defer resp.Body.Close() + bytes, err := io.ReadAll(resp.Body) + if err != nil { + panic("Failing to read the body") + } + + err = json.Unmarshal(bytes, &data) + if err != nil { + panic(err) + } + + return &data +} + +func ExtractContentId(url string) string { + r := regexp.MustCompile(`\d+`) + id := r.FindString(url) + return id +} + +func GetDownloadUrl(data *ContentPageData) string { + return fmt.Sprintf("https:%s", data.Data.MainContent.Medias[0].Src.File) +} diff --git a/downloader/downloader_test.go b/downloader/downloader_test.go new file mode 100644 index 0000000..9b3ed01 --- /dev/null +++ b/downloader/downloader_test.go @@ -0,0 +1,56 @@ +package downloader_test + +import ( + "jupiter_downloader/downloader" + "net/http" + "testing" +) + +func TestIdExtract(t *testing.T) { + testUrl := "https://jupiter.err.ee/1038278/aktuaalne-kaamera" + expectedId := "1038278" + + actual := downloader.ExtractContentId(testUrl) + + if expectedId != actual { + t.Fatalf("Expected %s, got %s", expectedId, actual) + } +} + +func TestGetContentPageData(t *testing.T) { + testUrl := "https://jupiter.err.ee/1038278/aktuaalne-kaamera" + id := downloader.ExtractContentId(testUrl) + data := downloader.GetContentPageData(id) + medias := data.Data.MainContent.Medias + + if len(medias) == 0 { + t.Fatalf("Expected medias to contain items, got 0") + } + + for _, media := range medias { + file := media.Src.File + + if len(file) == 0 { + t.Fatalf("Invalid file name gotten") + } + + t.Logf("Media is %s", media.Src.File) + } +} + +func TestDownloadUrl(t *testing.T) { + testUrl := "https://jupiter.err.ee/1038278/aktuaalne-kaamera" + id := downloader.ExtractContentId(testUrl) + data := downloader.GetContentPageData(id) + url := downloader.GetDownloadUrl(data) + + resp, err := http.Get(url) + + if err != nil { + t.Fatal(err) + } + + if resp.StatusCode != http.StatusOK { + t.Fatalf("bad status: %s", resp.Status) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..6652d2f --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module jupiter_downloader + +go 1.22.7 diff --git a/main.go b/main.go new file mode 100644 index 0000000..73a3ed0 --- /dev/null +++ b/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "jupiter_downloader/downloader" +) + +func main() { + // downloader.Download("1038278") + // downloader.Download("https://jupiter.err.ee/1038278/aktuaalne-kaamera", "") + // downloader.DownloadSingle("https://jupiter.err.ee/1609406782/babulon-berliin", "", "ET") + downloader.DownloadSeason("https://jupiter.err.ee/1235599/babulon-berliin", "4", "ET") + // fs := http.FileServer(http.Dir("static/")) + // + // http.Handle("/", fs) + // + // fmt.Println("Listening on 8080") + // http.ListenAndServe(":8080", nil) +}