Skip to content
This repository was archived by the owner on Dec 1, 2025. It is now read-only.

Commit 30b129d

Browse files
authored
Merge pull request #20 from xeyossr/feat/history
En son izlenen bölümü hatırlama özelliği
2 parents bb7b945 + a37d071 commit 30b129d

File tree

6 files changed

+210
-17
lines changed

6 files changed

+210
-17
lines changed

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
- **Cross-Platform**: Linux, Windows ve macOS üzerinde çalışabilir.
2424
- **AnimeCix ve OpenAnime Entegrasyonu**: Popüler anime platformlarından hızlı arama ve izleme imkanı.
2525
- **Fansub Seçimi**: OpenAnime üzerinden izlerken favori çeviri grubunuzu seçme özgürlüğü.
26+
- **Bölüm Takibi**: İzlediğiniz animenin en son bölümünü hatırlayarak bir sonraki bölümden başlar.
2627
- **Çoklu Arayüz Desteği**: Terminal tabanlı TUI ve minimalist grafik arayüz (Rofi UI) seçenekleri.
28+
- **Anime İndirme Özelliği**: İzlediğiniz animeleri cihazınıza indirip çevrimdışı izleme imkanı.
2729
- **Discord Rich Presence**: İzlediğiniz animeyi Discord profilinizde paylaşın.
2830
- **Otomatik Güncelleme Kontrolü**: Uygulama her başlatıldığında yeni sürüm olup olmadığını kontrol eder.
2931

@@ -59,7 +61,7 @@ make install-linux
5961
> **Gereksinimler:**
6062
> Derleme: `go`, `git`, `make`
6163
> Kullanım: `mpv`
62-
> İsteğe bağlı: `rofi` (Rofi arayüzü için)
64+
> İsteğe bağlı: `rofi` (Rofi arayüzü için), `youtube-dl`/`yt-dlp` (Bölüm indirme özelliği için)
6365
6466
**Paketleri yüklemek için:**
6567

@@ -91,6 +93,7 @@ make install-linux
9193
3. `C:\Program Files\anitr-cli` klasörünü oluşturun.
9294
4. `anitr-cli.exe` dosyasını bu klasöre taşıyın.
9395
5. PATH’e `C:\Program Files\anitr-cli` ekleyin.
96+
6. Anime indirebilmek için [yt-dlp](https://github.com/yt-dlp/yt-dlp/releases/latest) veya [youtube-dl](https://github.com/ytdl-org/youtube-dl/releases) indirin ve PATH'e ekleyin. (Opsiyonel)
9497

9598
Artık **cmd** veya **PowerShell** içinde anitr-cli çalıştırabilirsiniz.
9699

@@ -108,6 +111,18 @@ git fetch --tags
108111
make install-macos
109112
```
110113

114+
Anime indirebilmek için [yt-dlp](https://github.com/yt-dlp/yt-dlp/releases/latest) veya [youtube-dl](https://github.com/ytdl-org/youtube-dl/releases) yüklemeniz gerekmektedir:
115+
116+
```bash
117+
brew install yt-dlp
118+
```
119+
120+
ya da
121+
122+
```bash
123+
brew install youtube-dl
124+
```
125+
111126
---
112127

113128
## 🚀 Kullanım

aur/.SRCINFO

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pkgbase = anitr-cli
22
pkgdesc = 🚀 Terminalde Türkçe altyazılı anime arama ve izleme aracı
3-
pkgver = 4.3.4
3+
pkgver = 4.4.0
44
pkgrel = 1
55
url = https://github.com/xeyossr/anitr-cli
66
arch = any
@@ -10,7 +10,9 @@ pkgbase = anitr-cli
1010
depends = mpv
1111
optdepends = rofi: X11 kullanıcıları için GUI
1212
optdepends = rofi-wayland: Wayland kullanıcıları için GUI
13-
source = anitr-cli-4.3.4.tar.gz::https://github.com/xeyossr/anitr-cli/archive/refs/tags/v4.3.4.tar.gz
13+
optdepends = youtube-dl: Anime indirme özelliği için
14+
optdepends = yt-dlp: Anime indirme özelliği için
15+
source = anitr-cli-4.4.0.tar.gz::https://github.com/xeyossr/anitr-cli/archive/refs/tags/v4.4.0.tar.gz
1416
sha256sums = SKIP
1517

1618
pkgname = anitr-cli

aur/PKGBUILD

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Maintainer: xeyossr
22
# Description: 🚀 Terminalde Türkçe altyazılı anime arama ve izleme aracı
33
pkgname=anitr-cli
4-
pkgver=4.3.4
4+
pkgver=4.4.0
55
pkgrel=1
66
pkgdesc="🚀 Terminalde Türkçe altyazılı anime arama ve izleme aracı"
77
arch=('any')
@@ -11,20 +11,22 @@ depends=('mpv')
1111
makedepends=('go' 'git')
1212

1313
optdepends=(
14-
'rofi: X11 kullanıcıları için GUI'
15-
'rofi-wayland: Wayland kullanıcıları için GUI'
14+
'rofi: X11 kullanıcıları için GUI'
15+
'rofi-wayland: Wayland kullanıcıları için GUI'
16+
'youtube-dl: Anime indirme özelliği için'
17+
'yt-dlp: Anime indirme özelliği için'
1618
)
1719

1820
source=("${pkgname}-${pkgver}.tar.gz::https://github.com/xeyossr/anitr-cli/archive/refs/tags/v${pkgver}.tar.gz")
1921
sha256sums=('SKIP')
2022

2123
build() {
22-
gobuildenv=$(go version)
23-
cd "$srcdir/$pkgname-$pkgver"
24-
go build -o build/anitr-cli -ldflags="-X 'github.com/xeyossr/anitr-cli/internal/update.version=${pkgver}' -X 'github.com/xeyossr/anitr-cli/internal/update.buildEnv=${gobuildenv}'"
24+
gobuildenv=$(go version)
25+
cd "$srcdir/$pkgname-$pkgver"
26+
go build -o build/anitr-cli -ldflags="-X 'github.com/xeyossr/anitr-cli/internal/update.version=${pkgver}' -X 'github.com/xeyossr/anitr-cli/internal/update.buildEnv=${gobuildenv}'"
2527
}
2628

2729
package() {
28-
cd "$srcdir/$pkgname-$pkgver"
29-
install -Dm755 build/anitr-cli "${pkgdir}/usr/bin/${pkgname}"
30+
cd "$srcdir/$pkgname-$pkgver"
31+
install -Dm755 build/anitr-cli "${pkgdir}/usr/bin/${pkgname}"
3032
}

internal/dl/dl.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,17 @@ func NewDownloader(baseDir string) (*Downloader, error) {
4040
}
4141

4242
// Download -> anime adı + bölüm + url alır, dosyayı indirir
43-
func (d *Downloader) Download(animeName, episode, url string) error {
44-
// Çıkış klasörü: ~/Videos/anitr-cli/AnimeName
45-
outDir := filepath.Join(d.BaseDir, animeName)
43+
func (d *Downloader) Download(source, animeName, episode, url string) error {
44+
// Çıkış klasörü: ~/Videos/anitr-cli/source/animeName
45+
// örnek: ~/Videos/anitr-cli/openanime/Bungo Stray Dogs
46+
outDir := filepath.Join(d.BaseDir, source, animeName)
4647
err := os.MkdirAll(outDir, 0o755)
4748
if err != nil {
4849
return fmt.Errorf("klasör oluşturulamadı: %w", err)
4950
}
5051

5152
// Dosya adı formatı: AnimeName-Episode.mp4
52-
outFile := filepath.Join(outDir, fmt.Sprintf("%s-%s.%%(ext)s", animeName, episode))
53+
outFile := filepath.Join(outDir, fmt.Sprintf("%s.%%(ext)s", episode))
5354

5455
// Komutu çalıştır
5556
cmd := exec.Command(d.BinPath, "-o", outFile, url)

internal/utils/history.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package utils
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"runtime"
9+
"time"
10+
11+
"github.com/xeyossr/anitr-cli/internal/player"
12+
)
13+
14+
// AnimeHistoryEntry, history.json içindeki her anime için kullanılacak
15+
type AnimeHistoryEntry map[string]interface{}
16+
17+
// AnimeHistory, source -> anime adı -> alanlar
18+
type AnimeHistory map[string]map[string]AnimeHistoryEntry
19+
20+
// getHistoryPath cross-platform olarak history.json yolunu döndürür
21+
func getHistoryPath() (string, error) {
22+
var historyDir string
23+
if runtime.GOOS == "windows" {
24+
appData := os.Getenv("APPDATA")
25+
if appData == "" {
26+
appData = os.Getenv("USERPROFILE")
27+
if appData == "" {
28+
return "", fmt.Errorf("APPDATA ve USERPROFILE bulunamadı")
29+
}
30+
}
31+
historyDir = filepath.Join(appData, "anitr-cli")
32+
} else {
33+
home := os.Getenv("HOME")
34+
if home == "" {
35+
return "", fmt.Errorf("HOME bulunamadı")
36+
}
37+
historyDir = filepath.Join(home, ".anitr-cli")
38+
}
39+
40+
// Klasör yoksa oluştur
41+
if err := os.MkdirAll(historyDir, 0o755); err != nil {
42+
return "", fmt.Errorf("history klasörü oluşturulamadı: %w", err)
43+
}
44+
45+
return filepath.Join(historyDir, "history.json"), nil
46+
}
47+
48+
// ReadAnimeHistory history.json'u okur, yoksa yeni oluşturur
49+
func ReadAnimeHistory() (AnimeHistory, error) {
50+
path, err := getHistoryPath()
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
data, err := os.ReadFile(path)
56+
if err != nil {
57+
if os.IsNotExist(err) {
58+
return make(AnimeHistory), nil
59+
}
60+
return nil, fmt.Errorf("history okunamadı: %w", err)
61+
}
62+
63+
var history AnimeHistory
64+
if err := json.Unmarshal(data, &history); err != nil {
65+
return nil, fmt.Errorf("history parse edilemedi: %w", err)
66+
}
67+
return history, nil
68+
}
69+
70+
// WriteAnimeHistory history.json'u yazar
71+
func WriteAnimeHistory(history AnimeHistory) error {
72+
path, err := getHistoryPath()
73+
if err != nil {
74+
return err
75+
}
76+
data, err := json.MarshalIndent(history, "", " ")
77+
if err != nil {
78+
return fmt.Errorf("history serialize edilemedi: %w", err)
79+
}
80+
if err := os.WriteFile(path, data, 0o644); err != nil {
81+
return fmt.Errorf("history yazılamadı: %w", err)
82+
}
83+
return nil
84+
}
85+
86+
// GetLastEpisodeIndex, source ve anime adı ile son izlenen bölümü döndürür
87+
func GetLastEpisodeIndex(source, animeName string) (int, error) {
88+
history, err := ReadAnimeHistory()
89+
if err != nil {
90+
return -1, err
91+
}
92+
93+
sourceEntry, ok := history[source]
94+
if !ok {
95+
return -1, nil
96+
}
97+
98+
animeEntry, ok := sourceEntry[animeName]
99+
if !ok {
100+
return -1, nil
101+
}
102+
103+
if idx, ok := animeEntry["lastEpisodeIdx"]; ok {
104+
if i, ok := idx.(float64); ok {
105+
return int(i), nil
106+
}
107+
}
108+
109+
return -1, nil
110+
}
111+
112+
// UpdateAnimeHistory, mevcut MPV oturumu sırasında animeyi history.json'a kaydeder
113+
func UpdateAnimeHistory(socketPath, source, animeName, key string, episodeIndex int, logger *Logger) {
114+
ticker := time.NewTicker(10 * time.Second)
115+
defer ticker.Stop()
116+
117+
updated := false
118+
for range ticker.C {
119+
if !player.IsMPVRunning(socketPath) {
120+
break
121+
}
122+
123+
durationVal, err1 := player.MPVSendCommand(socketPath, []interface{}{"get_property", "duration"})
124+
timePosVal, err2 := player.MPVSendCommand(socketPath, []interface{}{"get_property", "time-pos"})
125+
if err1 != nil || err2 != nil {
126+
continue
127+
}
128+
129+
duration, ok1 := durationVal.(float64)
130+
progress, ok2 := timePosVal.(float64)
131+
if !ok1 || !ok2 {
132+
continue
133+
}
134+
135+
if updated {
136+
continue
137+
}
138+
139+
if progress >= duration-300 { // son 5 dakika
140+
history, err := ReadAnimeHistory()
141+
if err != nil {
142+
logger.LogError(err)
143+
continue
144+
}
145+
146+
sourceEntry, ok := history[source]
147+
if !ok {
148+
sourceEntry = make(map[string]AnimeHistoryEntry)
149+
}
150+
151+
animeEntry, ok := sourceEntry[animeName]
152+
if !ok {
153+
animeEntry = make(AnimeHistoryEntry)
154+
}
155+
156+
animeEntry[key] = episodeIndex
157+
sourceEntry[animeName] = animeEntry
158+
history[source] = sourceEntry
159+
160+
if err := WriteAnimeHistory(history); err != nil {
161+
logger.LogError(err)
162+
continue
163+
}
164+
updated = true
165+
}
166+
}
167+
}

main.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,10 @@ func playAnimeLoop(
477477
selectedResolution := ""
478478
selectedResolutionIdx := 0
479479

480+
if lastEpisodeIdx, err := utils.GetLastEpisodeIndex(source.Source(), selectedAnimeName); err == nil && lastEpisodeIdx >= 0 && len(episodes) > lastEpisodeIdx+1 {
481+
// Eğer daha önce izlenmişse bir sonraki bölüm
482+
selectedEpisodeIndex = lastEpisodeIdx + 1
483+
}
480484
// Discord RPC için giriş yap
481485
loggedIn, err := rpc.ClientLogin()
482486
if err != nil || !loggedIn {
@@ -608,11 +612,13 @@ func playAnimeLoop(
608612
return source, selectedSource
609613
}
610614

611-
// Discord RPC'yi başlat
612615
if !disableRPC {
613616
go updateDiscordRPC(socketPath, episodeNames, selectedEpisodeIndex, selectedAnimeName, selectedSource, posterURL, logger, &loggedIn)
614617
}
615618

619+
// History güncelleme için goroutine
620+
go utils.UpdateAnimeHistory(socketPath, source.Source(), selectedAnimeName, "lastEpisodeIdx", selectedEpisodeIndex, logger)
621+
616622
// Oynatma işlemi tamamlanana kadar bekle
617623
err = cmd.Wait()
618624
if err != nil {
@@ -796,7 +802,7 @@ func playAnimeLoop(
796802
fmt.Printf("\033[31m[!] %s için URL bulunamadı.\033[0m\n", ep.Title)
797803
continue
798804
}
799-
err := downloader.Download(selectedAnimeName, ep.Title, url)
805+
err := downloader.Download(source.Source(), selectedAnimeName, ep.Title, url)
800806
if err != nil {
801807
fmt.Printf("\033[31m[!] %s indirilemedi: %s\033[0m\n", ep.Title, err)
802808
}

0 commit comments

Comments
 (0)