mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-12 15:50:01 -08:00
Merge pull request #93 from iMithrellas/manga-icat
This pull request introduces a new manga viewer option, icat.
This commit is contained in:
@@ -66,7 +66,9 @@ def search(config: "Config", anime_titles: str, episode_range: str):
|
||||
from yt_dlp.utils import sanitize_filename
|
||||
|
||||
from ...MangaProvider import MangaProvider
|
||||
|
||||
from ..utils.feh import feh_manga_viewer
|
||||
from ..utils.icat import icat_manga_viewer
|
||||
|
||||
manga_title = anime_titles[0]
|
||||
|
||||
@@ -136,7 +138,12 @@ def search(config: "Config", anime_titles: str, episode_range: str):
|
||||
print(
|
||||
f"[purple bold]Now Reading: [/] {search_result_manga_title} [cyan bold]Chapter:[/] {chapter_info['title']}"
|
||||
)
|
||||
feh_manga_viewer(chapter_info["thumbnails"], str(chapter_info["title"]))
|
||||
if config.manga_viewer == "feh":
|
||||
feh_manga_viewer(chapter_info["thumbnails"], str(chapter_info["title"]))
|
||||
elif config.manga_viewer == "icat":
|
||||
icat_manga_viewer(
|
||||
chapter_info["thumbnails"], str(chapter_info["title"])
|
||||
)
|
||||
if anilist_helper:
|
||||
anilist_helper.update_anime_list(
|
||||
{"mediaId": anilist_id, "progress": chapter_number}
|
||||
|
||||
@@ -42,6 +42,7 @@ class Config(object):
|
||||
default_config = {
|
||||
"auto_next": "False",
|
||||
"menu_order": "",
|
||||
"manga_viewer": "feh",
|
||||
"auto_select": "True",
|
||||
"cache_requests": "true",
|
||||
"check_for_updates": "True",
|
||||
@@ -187,6 +188,7 @@ class Config(object):
|
||||
self.skip = self.configparser.getboolean("stream", "skip")
|
||||
self.sort_by = self.configparser.get("anilist", "sort_by")
|
||||
self.menu_order = self.configparser.get("general", "menu_order")
|
||||
self.manga_viewer = self.configparser.get("general", "manga_viewer")
|
||||
self.sub_lang = self.configparser.get("general", "sub_lang")
|
||||
self.translation_type = self.configparser.get("stream", "translation_type")
|
||||
self.use_fzf = self.configparser.getboolean("general", "use_fzf")
|
||||
@@ -476,6 +478,11 @@ mpv_args = {self.mpv_args}
|
||||
# useful incase of wanting to run sth like: kitty mpv --vo=kitty <url>
|
||||
mpv_pre_args = {self.mpv_pre_args}
|
||||
|
||||
# choose manga viewer [feh/icat]
|
||||
# feh is the default and requires feh to be installed
|
||||
# icat is for kitty terminal users only
|
||||
manga_viewer = {self.manga_viewer}
|
||||
|
||||
[stream]
|
||||
# the quality of the stream [1080,720,480,360]
|
||||
# this option is usually only reliable when:
|
||||
|
||||
102
fastanime/cli/utils/icat.py
Normal file
102
fastanime/cli/utils/icat.py
Normal file
@@ -0,0 +1,102 @@
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import termios
|
||||
import tty
|
||||
from sys import exit
|
||||
|
||||
from rich.console import Console
|
||||
from rich.panel import Panel
|
||||
from rich.align import Align
|
||||
from rich.text import Text
|
||||
|
||||
console = Console()
|
||||
|
||||
|
||||
def get_key():
|
||||
"""Read a single keypress (including arrows)."""
|
||||
fd = sys.stdin.fileno()
|
||||
old = termios.tcgetattr(fd)
|
||||
try:
|
||||
tty.setraw(fd)
|
||||
ch1 = sys.stdin.read(1)
|
||||
if ch1 == "\x1b":
|
||||
ch2 = sys.stdin.read(2)
|
||||
return ch1 + ch2
|
||||
return ch1
|
||||
finally:
|
||||
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||
|
||||
|
||||
def draw_banner_at(msg: str, row: int):
|
||||
"""Move cursor to `row`, then render a centered, cyan-bordered panel."""
|
||||
sys.stdout.write(f"\x1b[{row};1H")
|
||||
text = Text(msg, justify="center")
|
||||
panel = Panel(Align(text, align="center"), border_style="cyan", padding=(1, 2))
|
||||
console.print(panel)
|
||||
|
||||
|
||||
def icat_manga_viewer(image_links: list[str], window_title: str):
|
||||
ICAT = shutil.which("kitty")
|
||||
if not ICAT:
|
||||
console.print("[bold red]kitty (for icat) not found[/]")
|
||||
exit(1)
|
||||
|
||||
idx, total = 0, len(image_links)
|
||||
title = f"{window_title} ({total} images)"
|
||||
show_banner = True
|
||||
|
||||
try:
|
||||
while True:
|
||||
console.clear()
|
||||
term_width, term_height = shutil.get_terminal_size((80, 24))
|
||||
panel_height = 0
|
||||
|
||||
# Calculate space for image based on banner visibility
|
||||
if show_banner:
|
||||
msg_lines = 3 # Title + blank + controls
|
||||
panel_height = msg_lines + 4 # Padding and borders
|
||||
image_height = term_height - panel_height - 1
|
||||
else:
|
||||
image_height = term_height
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
ICAT,
|
||||
"+kitten",
|
||||
"icat",
|
||||
"--clear",
|
||||
"--scale-up",
|
||||
"--place",
|
||||
f"{term_width}x{image_height}@0x0",
|
||||
"--z-index",
|
||||
"-1",
|
||||
image_links[idx],
|
||||
]
|
||||
)
|
||||
|
||||
if show_banner:
|
||||
controls = (
|
||||
f"[{idx + 1}/{total}] Prev: [h/←] Next: [l/→] "
|
||||
f"Toggle Banner: [b] Quit: [q/Ctrl-C]"
|
||||
)
|
||||
msg = f"{title}\n\n{controls}"
|
||||
start_row = term_height - panel_height
|
||||
draw_banner_at(msg, start_row)
|
||||
|
||||
# key handling
|
||||
key = get_key()
|
||||
if key in ("l", "\x1b[C"):
|
||||
idx = (idx + 1) % total
|
||||
elif key in ("h", "\x1b[D"):
|
||||
idx = (idx - 1) % total
|
||||
elif key == "b":
|
||||
show_banner = not show_banner
|
||||
elif key in ("q", "\x03"):
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
console.clear()
|
||||
console.print("Exited viewer.", style="bold")
|
||||
Reference in New Issue
Block a user