-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6d33cad
commit 21eca8e
Showing
13 changed files
with
795 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,7 @@ go.work.sum | |
|
||
# env file | ||
.env | ||
|
||
dist/ | ||
bin/ | ||
tmp/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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:" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
) |
Oops, something went wrong.