Skip to content

Commit

Permalink
feat: 添加girigirilove源 & 修改tui界面 & 添加播放器菜单 & docs: 完善README
Browse files Browse the repository at this point in the history
  • Loading branch information
h3ll0www0rld committed May 2, 2024
1 parent f7b1eeb commit 7d08c3f
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 73 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
# ani-cli-cn
一个使用国内播放源的`ani-cli`,使你能通过终端来看番
一个更适合中国宝宝体制的`ani-cli`

# 支持源列表
- iyinghua

目前只支持这个
- girigirilove

# 下载
请到`Github Actions`中的工件下载<br>
[h3ll0www0rld/ani-cli-cn/actions](https://github.com/h3ll0www0rld/ani-cli-cn/actions)

# 安装
请确保`mpv`在你的环境变量中(在终端输入`mpv --version`有输出)
本项目使用`mpv`作为播放器,请确保`mpv`在你的环境变量中(在终端输入`mpv --version`有输出)
## Windows
```shell
scoop install mpv
```

# 使用
本项目有完整的`tui`,易于使用,这里不多说明
## Windows
```shell
./ani-cli.exe
```
## Linux & Mac
```shell
./ani-cli
```

# 开发&构建
在项目根目录下先运行
Expand Down
50 changes: 50 additions & 0 deletions api/girigirilove.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 需要cookie
from requests_html import HTMLSession


class GiriGiriLove:
def __init__(self) -> None:
self.SESSION = HTMLSession()
self.BASE_URL = "https://anime.girigirilove.com"

def search(self, keyword: str) -> str:
page_number = 1
titles = []
hrefs = []
while True:
search_url = f"{self.BASE_URL}/search/{keyword}----------{page_number}---/"
response = self.SESSION.get(search_url)
thumb_txts = response.html.find(".thumb-txt.cor4.hide")
if not thumb_txts:
break
divs = response.html.find("div.left.public-list-bj")
for i in range(min(len(thumb_txts), len(divs))):
thumb_txt_text = thumb_txts[i].text
div_href = divs[i].find("a")[0].attrs["href"]
titles.append(thumb_txt_text)
hrefs.append(div_href)
page_number += 1
return titles, hrefs

def episodes(self, page_href: str) -> list[str]:
response = self.SESSION.get(self.BASE_URL + page_href)
ul = response.html.find("ul.anthology-list-play.size", first=True)
hrefs = ul.find("li a")
video_page_hrefs = [href.attrs["href"] for href in hrefs]
return self.changeToSC(sorted(video_page_hrefs))

def play(self, page_href: str) -> str:
response = self.SESSION.get(self.BASE_URL + page_href)
response.html.render()
src = response.html.find("td#playleft iframe", first=True).attrs["src"]
return src.split("=")[-1]

def changeToSC(self, video_page_hrefs: list[str]):
test_video_page_href = video_page_hrefs[0].replace("-1-", "-2-")
response = self.SESSION.get(self.BASE_URL + test_video_page_href)
if "m3u8" in response.html.html or "mp4" in response.html.html:
return video_page_hrefs
return [
video_page_href.replace("-1-", "-2-")
for video_page_href in video_page_hrefs
]
27 changes: 14 additions & 13 deletions api/iyinghua.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@

class IYingHua:
def __init__(self) -> None:
self.session = HTMLSession()
self.SESSION = HTMLSession()
self.BASE_URL = "http://www.iyinghua.io"

def search(self, keyword: str) -> str:
page_number = 1
titles = []
links = []
hrefs = []
while True:
search_url = f"http://www.iyinghua.io/search/{keyword}?page={page_number}"
response = self.session.get(search_url)
search_url = f"{self.BASE_URL}/search/{keyword}?page={page_number}"
response = self.SESSION.get(search_url)
try:
items = response.html.find("li > h2 > a")
except:
Expand All @@ -20,23 +21,23 @@ def search(self, keyword: str) -> str:
break
for item in items:
titles.append(item.attrs["title"])
links.append(item.attrs["href"])
hrefs.append(item.attrs["href"])
page_number += 1
return titles, links
return titles, hrefs

def episode(self, page_url: str) -> list[str]:
response = self.session.get(page_url)
video_links = []
def episodes(self, page_href: str) -> list[str]:
response = self.SESSION.get(self.BASE_URL + page_href)
video_page_hrefs = []
ul_elements = response.html.find("div.movurl > ul")
for ul in ul_elements:
li_elements = ul.find("li")
for li in li_elements:
href = li.find("a", first=True).attrs.get("href")
video_links.append(href)
return sorted(video_links)
video_page_hrefs.append(href)
return sorted(video_page_hrefs)

def play(self, page_url: str) -> str:
response = self.session.get(page_url)
def play(self, page_href: str) -> str:
response = self.SESSION.get(self.BASE_URL + page_href)
data_vid = None
div_element = response.html.find("div.bofang > div[data-vid]", first=True)
if div_element:
Expand Down
22 changes: 16 additions & 6 deletions mpv.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import subprocess
import psutil
import sys


class MPV:
def __init__(self) -> None:
pass

def play(self, url: str) -> None:
subprocess.run(
def __init__(self, url: str) -> None:
if sys.platform.startswith("linux") or sys.platform.startswith("darwin"):
self.process_name = "mpv"
elif sys.platform.startswith("win32"):
self.process_name = "mpv.exe"
else:
raise NotImplementedError("Unsupported platform")
process = subprocess.Popen(
["mpv", url],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
shell=True,
)

def close(self) -> None:
for process in psutil.process_iter():
process_info = process.as_dict(attrs=["pid", "name"])
if process_info["name"] == self.process_name:
process.terminate()
4 changes: 1 addition & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
blessed
requests_html
lxml_html_clean
pyinstaller
# windows
windows-curses
psutil
File renamed without changes.
28 changes: 7 additions & 21 deletions tui/Selector.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import curses
import questionary


class Selector:
def __init__(self, stdscr, options):
curses.curs_set(0)
selected_option = 0
def __init__(self, prompt, options):
self.prompt = prompt
self.options = options

while True:
stdscr.clear()
for index, option in enumerate(options):
if index == selected_option:
stdscr.addstr(index, 0, option, curses.color_pair(1))
else:
stdscr.addstr(index, 0, option)

stdscr.refresh()
key = stdscr.getch()
if key == curses.KEY_UP:
selected_option = max(0, selected_option - 1)
elif key == curses.KEY_DOWN:
selected_option = min(len(options) - 1, selected_option + 1)
elif key == curses.KEY_ENTER or key in [10, 13]:
self.selected_item_index = selected_option
break
def show(self):
selected_option = questionary.select(self.prompt, choices=self.options).ask()
return self.options.index(selected_option)
10 changes: 10 additions & 0 deletions tui/TextInputer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import questionary


class TextInputer:
def __init__(self, prompt):
self.prompt = prompt

def show(self):
input_text = questionary.text(self.prompt).ask()
return input_text
79 changes: 54 additions & 25 deletions tui/Tui.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,69 @@
from tui.Selector import Selector
from tui.TextInputer import TextInputer
from api.iyinghua import IYingHua
from api.girigirilove import GiriGiriLove
from mpv import MPV
import curses
import os


def main() -> None:
keyword = input("KeyWord => ")
source_list = ["iyinghua"]

# curses selector
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
curses.noecho()
stdscr.keypad(True)
keyword = TextInputer("搜索关键词:").show()
source_list = ["iyinghua", "girigirilove"]
player_function_list = ["上一集", "下一集", "选择集数", "退出"]

# 选择源
selected_source_index = Selector(stdscr, source_list).selected_item_index
selected_source_index = Selector("选择一个源:", source_list).show()
if selected_source_index == 0:
session = IYingHua()
if selected_source_index == 1:
session = GiriGiriLove()

# 选择番
titles, links = session.search(keyword)
selected_ani_index = Selector(stdscr, titles).selected_item_index
if titles == []:
print("错误,搜索无结果")
exit()
os.system("cls" if os.name == "nt" else "clear")
selected_ani_index = Selector("选择一部番:", titles).show()

# 选择集数
video_links = session.episode(f"http://www.iyinghua.io" + links[selected_ani_index])
video_page_hrefs = session.episodes(links[selected_ani_index])
os.system("cls" if os.name == "nt" else "clear")
selected_episode_index = Selector(
stdscr, [f"第{i+1}集" for i in range(len(video_links))]
).selected_item_index
"选择集数:", [f"第{i+1}集" for i in range(len(video_page_hrefs))]
).show()
video_link = session.play(video_page_hrefs[selected_episode_index])
player = MPV(video_link)

curses.echo()
curses.endwin()
print("正在获取视频地址...")
m3u8_link = session.play(
f"http://www.iyinghua.io" + video_links[selected_episode_index]
)
print(f"获取成功,地址: {m3u8_link}")
print("正在调用mpv进行播放...")
player = MPV()
player.play(m3u8_link)
# 播放器菜单
while True:
if selected_episode_index == 0:
tmp_player_function_list = player_function_list[1:]
else:
tmp_player_function_list = player_function_list
os.system("cls" if os.name == "nt" else "clear")
selected_player_function_index = Selector(
f"播放器菜单(当前集数: 第{selected_episode_index+1}集):",
tmp_player_function_list,
).show()
if tmp_player_function_list[selected_player_function_index] == "上一集":
selected_episode_index -= 1
video_link = session.play(video_page_hrefs[selected_episode_index])
player.close()
player = MPV(video_link)
elif tmp_player_function_list[selected_player_function_index] == "下一集":
selected_episode_index += 1
video_link = session.play(video_page_hrefs[selected_episode_index])
player.close()
player = MPV(video_link)
elif tmp_player_function_list[selected_player_function_index] == "选择集数":
os.system("cls" if os.name == "nt" else "clear")
selected_episode_index = Selector(
"选择一集:", [f"第{i+1}集" for i in range(len(video_page_hrefs))]
).show()
video_link = session.play(video_page_hrefs[selected_episode_index])
player.close()
player = MPV(video_link)
elif tmp_player_function_list[selected_player_function_index] == "退出":
player.close()
break

0 comments on commit 7d08c3f

Please sign in to comment.