Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
StevenSermeus committed Aug 10, 2024
1 parent 6d33cad commit 21eca8e
Show file tree
Hide file tree
Showing 13 changed files with 795 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ go.work.sum

# env file
.env

dist/
bin/
tmp/
43 changes: 43 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com

# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj

version: 2

before:
hooks:
- go mod tidy

builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows

archives:
- format: tar.gz
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
# use zip for windows archives
format_overrides:
- goos: windows
format: zip

changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"
17 changes: 17 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
build:
CGO_ENABLED=0 go build -o bin/anime-tui

install:
make build
cp bin/anime-tui ~/.local/bin/anime-tui

dev:
go mod tidy
go run anime-tui.go

run:
go run anime-tui.go

build-all:
go mod tidy
goreleaser build --snapshot --clean
268 changes: 268 additions & 0 deletions anime-tui.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
package main

import (
"fmt"
"io"
"net/http"
"os"
"regexp"
"time"

"github.com/PuerkitoBio/goquery"
"github.com/StevenSermeus/anime-tui/network"
"github.com/StevenSermeus/anime-tui/tui"
"github.com/StevenSermeus/anime-tui/video"
"github.com/briandowns/spinner"
"github.com/charmbracelet/bubbles/list"
tea "github.com/charmbracelet/bubbletea"
)

func main() {
//This is bad code, but it's a proof of concept
state := "menu"
choice := tui.Item{}
episode_choice := tui.Item{}
decoded_xsrf := ""
mav_token := ""
for {
switch state {
case "menu":
choice := optionList()
if choice.Name == "Nouveaux épisodes" {
state = "newEpisodes"
}
if choice.Name == "Recherche" {
state = "search"
}
case "newEpisodes":
choice, decoded_xsrf, mav_token = newEpisodes()
if choice.Name == "Retour" {
state = "menu"
continue
}
play(choice.Url, decoded_xsrf, mav_token)
case "search":
choice, decoded_xsrf, mav_token = search()
if choice.Name == "Retour" {
state = "menu"
} else {
state = "episodeList"
}
case "episodeList":
episode_choice = episodeList(choice)
if episode_choice.Name == "Retour" {
state = "search"
continue
}
play(episode_choice.Url, decoded_xsrf, mav_token)
}
}
}

func play(url string, decoded_xsrf string, mav_token string) {
result, err := network.GetVideoLink(url, mav_token, decoded_xsrf)
if err != nil {
panic(err)
}
link := ""
d0000d := regexp.MustCompile(`https://d0000d.com`)
for _, res := range result {
if d0000d.MatchString(res) {
link = res
}
}
if link == "" {
panic("Couldn't find the video link")
}
s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
s.Start()
new_Link, _ := getD0000DLink1(link)
play_link, err := getD0000DLink2("https://d0000d.com" + new_Link)
s.Stop()
if err != nil {
panic(err)
}
player := video.VLC{}
player.Play(play_link, "Anime TUI")
}

func getD0000DLink2(url string) (string, error) {
//Sleep 1 second to avoid getting blocked
time.Sleep(1 * time.Second)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
fmt.Println("Error creating request:", err)
}

req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
req.Header.Set("Accept-Language", "en-GB,en-US;q=0.9,en;q=0.8")
req.Header.Set("Cache-Control", "max-age=0")
req.Header.Set("Cookie", "lang=1;")
req.Header.Set("DNT", "1")
req.Header.Set("Priority", "u=0, i")
req.Header.Set("Sec-CH-UA", `"Chromium";v="127", "Not)A;Brand";v="99"`)
req.Header.Set("Sec-CH-UA-Mobile", "?0")
req.Header.Set("Sec-CH-UA-Platform", `"macOS"`)
req.Header.Set("Sec-Fetch-Dest", "document")
req.Header.Set("Sec-Fetch-Mode", "navigate")
req.Header.Set("Sec-Fetch-Site", "none")
req.Header.Set("Sec-Fetch-User", "?1")
req.Header.Set("Upgrade-Insecure-Requests", "1")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending request:", err)
}
defer resp.Body.Close()

// Read the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
panic(err)
}
match := regexp.MustCompile(`href="(.*?)"`).FindAllString(string(body), -1)
video_link := ""
for _, url := range match {
if regexp.MustCompile(`mp4`).MatchString(url) {
video_link = url
}
}
if video_link == "" {
panic("Couldn't find the video link")
}
video_link = regexp.MustCompile(`href="`).ReplaceAllString(video_link, "")
video_link = video_link[:len(video_link)-1]
return video_link, nil
}

func getD0000DLink1(url string) (string, error) {
url = regexp.MustCompile(`/e/`).ReplaceAllString(url, "/d/")
res, err := http.Get(url)
if err != nil {
panic(err)
}
defer res.Body.Close()
doc, err := goquery.NewDocumentFromReader(res.Body)
if err != nil {
panic(err)
}

additional_link := ""
doc.Find("div.download-content a").Each(func(i int, s *goquery.Selection) {
link, _ := s.Attr("href")
additional_link = link
})
return additional_link, nil
}

func episodeList(choice tui.Item) tui.Item {
episodeList, err := network.GetEpisodeList(choice.Url)
if err != nil {
panic(err)
}
episode_list := []list.Item{}
for _, episode := range episodeList {
episode_list = append(episode_list, tui.Item{Name: episode[2], Url: episode[1]})
}
episode_list = append(episode_list, tui.Item{Name: "Retour", Url: "Retour à la recherche"})
m := tui.Model{List: list.New(episode_list, list.NewDefaultDelegate(), 0, 0)}
m.List.Title = "Liste des épisodes"

p := tea.NewProgram(m, tea.WithAltScreen())

mf, err := p.Run()
if err != nil {
panic(err)
}
m = mf.(tui.Model)
if m.Quiting {
os.Exit(0)
}
return m.Choice
}

func optionList() (choice tui.Item) {
options := []list.Item{
tui.Item{Name: "Nouveaux épisodes", Url: "Voir les derniers épisodes sortis"},
tui.Item{Name: "Recherche", Url: "Rechercher un anime par nom"},
tui.Item{Name: "Exit", Url: "Press Ctrl+C to quit"},
}

m := tui.Model{List: list.New(options, list.NewDefaultDelegate(), 0, 0)}
m.List.Title = "Anime TUI"

p := tea.NewProgram(m, tea.WithAltScreen())

mf, err := p.Run()
if err != nil {
panic(err)
}

m = mf.(tui.Model)
if m.Quiting || m.Choice.Name == "Exit" {
os.Exit(0)
return
}
return m.Choice
}

func newEpisodes() (choice tui.Item, decoded_xsrf string, mav_token string) {
s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
s.Start()
animeList, decoded_xsrf, mav_token, err := network.GetRecentEpisode()
s.Stop()
if err != nil {
panic(err)
}
episode_list := []list.Item{}
for _, anime := range animeList {
episode_list = append(episode_list, tui.Item{Name: anime[1], Url: anime[0]})
}
episode_list = append(episode_list, tui.Item{Name: "Retour", Url: "Retour au menu"})
m := tui.Model{List: list.New(episode_list, list.NewDefaultDelegate(), 0, 0)}
m.List.Title = "Derniers épisodes"

p := tea.NewProgram(m, tea.WithAltScreen())

mf, err := p.Run()
if err != nil {
panic(err)
}
m = mf.(tui.Model)
if m.Quiting {
os.Exit(0)
}
return m.Choice, decoded_xsrf, mav_token
}

func search() (choice tui.Item, decoded_xsrf string, mavToken string) {
s := spinner.New(spinner.CharSets[9], 100*time.Millisecond)
s.Start()
animeList, decoded_xsrf, mavToken, err := network.GetAnimeList()
s.Stop()
if err != nil {
panic(err)
}
episode_list := []list.Item{}
for _, anime := range animeList {
episode_list = append(episode_list, tui.Item{Name: anime[2], Url: anime[1]})
}
episode_list = append(episode_list, tui.Item{Name: "Retour", Url: "Retour au menu"})
m := tui.Model{List: list.New(episode_list, list.NewDefaultDelegate(), 0, 0)}
m.List.Title = "Tout les animes"

p := tea.NewProgram(m, tea.WithAltScreen())

mf, err := p.Run()
if err != nil {
panic(err)
}
m = mf.(tui.Model)
if m.Quiting {
os.Exit(0)
}
return m.Choice, decoded_xsrf, mavToken

}
7 changes: 7 additions & 0 deletions cache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package cache

import "time"

func write(key string, value []byte, expiration time.Duration) error {
return nil
}
40 changes: 40 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
module github.com/StevenSermeus/anime-tui

go 1.22.5

require (
github.com/PuerkitoBio/goquery v1.9.2
github.com/briandowns/spinner v1.23.1
github.com/charmbracelet/bubbles v0.18.0
github.com/charmbracelet/bubbletea v0.26.6
github.com/charmbracelet/lipgloss v0.12.1
)

require (
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/charmbracelet/x/input v0.1.0 // indirect
github.com/charmbracelet/x/term v0.1.1 // indirect
github.com/charmbracelet/x/windows v0.1.0 // indirect
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/fatih/color v1.7.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.2 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.24.0 // indirect
golang.org/x/term v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
)
Loading

0 comments on commit 21eca8e

Please sign in to comment.