mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-25 04:15:19 -08:00
feat(anime_screen):implement crude streaming with allanime api
This commit is contained in:
@@ -1,6 +1,4 @@
|
||||
from kivy.cache import Cache
|
||||
from kivy.clock import Clock
|
||||
from kivy.logger import Logger
|
||||
|
||||
from ..Model import AnimeScreenModel
|
||||
from ..View import AnimeScreenView
|
||||
@@ -18,25 +16,13 @@ class AnimeScreenController:
|
||||
def get_view(self) -> AnimeScreenView:
|
||||
return self.view
|
||||
|
||||
def update_anime_view(self, id: int, caller_screen_name: str):
|
||||
"""method called to update the anime screen when a new
|
||||
def fetch_streams(self, anime_title, episode="1"):
|
||||
self.view.current_anime_data = self.model.get_anime_data_from_provider(
|
||||
anime_title
|
||||
)
|
||||
self.view.current_links = self.model.get_episode_streams(episode)
|
||||
|
||||
Args:
|
||||
id (int): the anilst id of the anime
|
||||
caller_screen_name (str): the screen thats calling this method; used internally to switch back to this screen
|
||||
"""
|
||||
if self.model.anime_id != id:
|
||||
if cached_anime_data := Cache.get("data.anime", f"{id}"):
|
||||
data = cached_anime_data
|
||||
else:
|
||||
data = self.model.get_anime_data(id)
|
||||
|
||||
if data[0]:
|
||||
self.model.anime_id = id
|
||||
Clock.schedule_once(
|
||||
lambda _: self.view.update_layout(
|
||||
data[1]["data"]["Page"]["media"][0], caller_screen_name
|
||||
)
|
||||
)
|
||||
Logger.info(f"Anime Screen:Success in opening anime of id: {id}")
|
||||
Cache.append("data.anime", f"{id}", data)
|
||||
def update_anime_view(self, id, title, caller_screen_name):
|
||||
self.fetch_streams(title)
|
||||
self.view.current_title = title
|
||||
self.view.caller_screen_name = caller_screen_name
|
||||
|
||||
@@ -120,9 +120,9 @@ class HomeScreenController:
|
||||
Clock.schedule_once(lambda _: self.trending_anime(), 1)
|
||||
Clock.schedule_once(lambda _: self.highest_scored_anime(), 2)
|
||||
Clock.schedule_once(lambda _: self.popular_anime(), 3)
|
||||
Clock.schedule_once(lambda _: self.favourite_anime(), 4)
|
||||
Clock.schedule_once(lambda _: self.recently_updated_anime(), 5)
|
||||
Clock.schedule_once(lambda _: self.upcoming_anime(), 6)
|
||||
# Clock.schedule_once(lambda _: self.favourite_anime(), 4)
|
||||
# Clock.schedule_once(lambda _: self.recently_updated_anime(), 5)
|
||||
# Clock.schedule_once(lambda _: self.upcoming_anime(), 6)
|
||||
|
||||
if self.populate_errors:
|
||||
show_notification(
|
||||
|
||||
@@ -21,8 +21,8 @@ class MyListScreenController:
|
||||
def __init__(self, model: MyListScreenModel):
|
||||
self.model = model
|
||||
self.view = MyListScreenView(controller=self, model=self.model)
|
||||
if len(self.requested_update_my_list_screen()) > 30:
|
||||
self.requested_update_my_list_screen(2)
|
||||
# if len(self.requested_update_my_list_screen()) > 30:
|
||||
# self.requested_update_my_list_screen(2)
|
||||
|
||||
def get_view(self) -> MyListScreenView:
|
||||
return self.view
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
from ..libs.anilist import AniList
|
||||
from .base_model import BaseScreenModel
|
||||
from ..libs.anime_provider.allanime_api import anime_provider
|
||||
from kivy.cache import Cache
|
||||
from fuzzywuzzy import fuzz
|
||||
|
||||
|
||||
def anime_title_percentage_match(
|
||||
possible_user_requested_anime_title: str, title: str
|
||||
) -> int:
|
||||
"""Returns the percentage match between the possible title and user title
|
||||
|
||||
Args:
|
||||
possible_user_requested_anime_title (str): an Animdl search result title
|
||||
title (str): the anime title the user wants
|
||||
|
||||
Returns:
|
||||
int: the percentage match
|
||||
"""
|
||||
print(locals())
|
||||
|
||||
percentage_ratio = fuzz.ratio(title, possible_user_requested_anime_title)
|
||||
print(percentage_ratio)
|
||||
return percentage_ratio
|
||||
|
||||
|
||||
Cache.register("streams.anime", limit=10)
|
||||
|
||||
|
||||
class AnimeScreenModel(BaseScreenModel):
|
||||
@@ -7,6 +32,48 @@ class AnimeScreenModel(BaseScreenModel):
|
||||
|
||||
data = {}
|
||||
anime_id = 0
|
||||
current_anime_data = None
|
||||
current_anime_id = "0"
|
||||
current_title = ""
|
||||
|
||||
def get_anime_data_from_provider(self, anime_title: str, id=None):
|
||||
if self.current_title == anime_title and self.current_anime_data:
|
||||
return self.current_anime_data
|
||||
|
||||
search_results = anime_provider.search_for_anime(anime_title)
|
||||
|
||||
if search_results:
|
||||
_search_results = search_results["shows"]["edges"]
|
||||
result = max(
|
||||
_search_results,
|
||||
key=lambda x: anime_title_percentage_match(x["name"], anime_title),
|
||||
)
|
||||
self.current_anime_id = result["_id"]
|
||||
self.current_anime_data = anime_provider.get_anime(result["_id"])
|
||||
self.current_title = anime_title
|
||||
return self.current_anime_data
|
||||
|
||||
def get_episode_streams(self, episode):
|
||||
if self.current_anime_data:
|
||||
episode_streams = anime_provider.get_anime_episode(
|
||||
self.current_anime_id, episode
|
||||
)
|
||||
streams = anime_provider.get_episode_streams(episode_streams)
|
||||
|
||||
if streams:
|
||||
_streams = list(streams)
|
||||
streams = []
|
||||
for stream in _streams:
|
||||
streams.append(
|
||||
{
|
||||
f"{stream[0]}": [
|
||||
_stream["link"] for _stream in stream[1]["links"]
|
||||
]
|
||||
}
|
||||
)
|
||||
return streams
|
||||
|
||||
# should return {type:{provider:streamlink}}
|
||||
|
||||
def get_anime_data(self, id: int):
|
||||
return AniList.get_anime(id)
|
||||
|
||||
@@ -19,10 +19,10 @@ class MediaCardDataLoader(object):
|
||||
media_card_data["anime_id"] = anime_id = anime_item["id"]
|
||||
|
||||
# TODO: ADD language preference
|
||||
if anime_item["title"].get("english"):
|
||||
media_card_data["title"] = anime_item["title"]["english"]
|
||||
else:
|
||||
if anime_item["title"].get("romaji"):
|
||||
media_card_data["title"] = anime_item["title"]["romaji"]
|
||||
else:
|
||||
media_card_data["title"] = anime_item["title"]["english"]
|
||||
|
||||
media_card_data["cover_image_url"] = anime_item["coverImage"]["medium"]
|
||||
|
||||
|
||||
@@ -1,61 +1,54 @@
|
||||
<AnimeBoxLayout@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
orientation:'vertical'
|
||||
|
||||
<AnimeLabel@MDLabel>:
|
||||
adaptive_height:True
|
||||
bold:True
|
||||
|
||||
<AnimeScreenView>:
|
||||
md_bg_color: self.theme_cls.backgroundColor
|
||||
header:header
|
||||
side_bar:side_bar
|
||||
rankings_bar:rankings_bar
|
||||
anime_description:anime_description
|
||||
anime_characters:anime_characters
|
||||
anime_reviews:anime_reviews
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
size_hint_y:None
|
||||
height: self.minimum_height
|
||||
MDBoxLayout:
|
||||
adaptive_height:True
|
||||
MDIconButton:
|
||||
icon: "arrow-left"
|
||||
on_release:
|
||||
root.manager_screens.current = root.caller_screen_name
|
||||
MDScrollView:
|
||||
size_hint:1,1
|
||||
MDBoxLayout:
|
||||
id:main_container
|
||||
size_hint_y:None
|
||||
padding:"10dp"
|
||||
spacing:"10dp"
|
||||
height: self.minimum_height
|
||||
orientation:"vertical"
|
||||
AnimeHeader:
|
||||
id:header
|
||||
MDBoxLayout:
|
||||
size_hint_y:None
|
||||
height: self.minimum_height
|
||||
AnimeSideBar:
|
||||
id:side_bar
|
||||
screen:root
|
||||
size_hint_y:None
|
||||
height:max(self.parent.height,self.minimum_height)
|
||||
adaptive_height:True
|
||||
MDIconButton:
|
||||
icon:"arrow-left"
|
||||
on_press:root.manager_screens.current = root.caller_screen_name
|
||||
MDTextField:
|
||||
on_text_validate:
|
||||
root.update_current_link(self)
|
||||
|
||||
VideoPlayer:
|
||||
source:root.current_link
|
||||
AnimeBoxLayout:
|
||||
AnimeLabel:
|
||||
text:"Sub"
|
||||
MDSegmentedButton:
|
||||
id:pl
|
||||
multiselect:False
|
||||
MDSegmentedButtonItem:
|
||||
on_active:
|
||||
pl.selected_segments = [self]
|
||||
root.update_current_video_stream("gogoanime")
|
||||
MDSegmentButtonLabel:
|
||||
text:"GoGoAnime"
|
||||
MDSegmentedButtonItem:
|
||||
on_active:
|
||||
root.update_current_video_stream("dropbox")
|
||||
pl.selected_segments = [self]
|
||||
MDSegmentButtonLabel:
|
||||
text:"DropBox"
|
||||
MDSegmentedButtonItem:
|
||||
on_active:
|
||||
root.update_current_video_stream("sharepoint")
|
||||
pl.selected_segments = [self]
|
||||
MDSegmentButtonLabel:
|
||||
text:"Share Point"
|
||||
MDSegmentedButtonItem:
|
||||
on_active:
|
||||
root.update_current_video_stream("wetransfer")
|
||||
pl.selected_segments = [self]
|
||||
MDSegmentButtonLabel:
|
||||
text:"weTransfer"
|
||||
|
||||
MDBoxLayout:
|
||||
spacing:"10dp"
|
||||
orientation:"vertical"
|
||||
size_hint_y:None
|
||||
height: max(self.parent.height,self.minimum_height)
|
||||
RankingsBar:
|
||||
id:rankings_bar
|
||||
Controls:
|
||||
screen:root
|
||||
cols:3 if root.width < 1100 else 5
|
||||
MDBoxLayout:
|
||||
adaptive_height:True
|
||||
padding:"20dp"
|
||||
orientation:"vertical"
|
||||
AnimeDescription:
|
||||
id:anime_description
|
||||
AnimeCharacters:
|
||||
id:anime_characters
|
||||
AnimeReviews:
|
||||
id:anime_reviews
|
||||
BoxLayout:
|
||||
|
||||
@@ -1,134 +1,33 @@
|
||||
from kivy.properties import DictProperty, ObjectProperty, StringProperty
|
||||
from kivy.properties import ListProperty, ObjectProperty, StringProperty
|
||||
|
||||
from ...libs.anilist import AnilistBaseMediaDataSchema
|
||||
from ...Utility import anilist_data_helper
|
||||
from ...View.base_screen import BaseScreenView
|
||||
from .components import (
|
||||
AnimdlStreamDialog,
|
||||
AnimeCharacters,
|
||||
AnimeDescription,
|
||||
AnimeHeader,
|
||||
AnimeReviews,
|
||||
AnimeSideBar,
|
||||
DownloadAnimeDialog,
|
||||
RankingsBar,
|
||||
)
|
||||
|
||||
|
||||
class AnimeScreenView(BaseScreenView):
|
||||
"""The anime screen view"""
|
||||
|
||||
caller_screen_name = StringProperty()
|
||||
header: AnimeHeader = ObjectProperty()
|
||||
side_bar: AnimeSideBar = ObjectProperty()
|
||||
rankings_bar: RankingsBar = ObjectProperty()
|
||||
anime_description: AnimeDescription = ObjectProperty()
|
||||
anime_characters: AnimeCharacters = ObjectProperty()
|
||||
anime_reviews: AnimeReviews = ObjectProperty()
|
||||
data = DictProperty()
|
||||
anime_id = 0
|
||||
current_link = StringProperty(
|
||||
"https://uc951f724c20bbec8df447bac605.dl.dropboxusercontent.com/cd/0/get/CUdx6k2qw-zqY86ftfFHqkmPqGuVrfjpE68B_EkcvZXcZLnjim_ZTHd-qNVb_mEbos9UsuhY8FJGdgf86RUZ-IJqZtz3tt8_CUVTloQAeZ47HtNiKjQ0ESvYdLuwqDjqwK2rNfsfiZI2cXBaKiUyJtljEeRL8whSff2wA9Z4tX1cow/file"
|
||||
)
|
||||
current_links = ListProperty([])
|
||||
current_anime_data = ObjectProperty()
|
||||
caller_screen_name = ObjectProperty()
|
||||
current_title = StringProperty()
|
||||
|
||||
def update_layout(self, data: AnilistBaseMediaDataSchema, caller_screen_name: str):
|
||||
self.caller_screen_name = caller_screen_name
|
||||
self.data = data
|
||||
# uitlity functions
|
||||
return
|
||||
|
||||
# variables
|
||||
english_title = data["title"]["english"]
|
||||
jp_title = data["title"]["romaji"]
|
||||
studios = data["studios"]["nodes"]
|
||||
def update_current_video_stream(self, server, is_dub=False):
|
||||
for link in self.current_links:
|
||||
if stream_link := link.get(server):
|
||||
print(link)
|
||||
self.current_link = stream_link[0]
|
||||
break
|
||||
# print(link)
|
||||
|
||||
# update header
|
||||
self.header.titles = f"{english_title}\n{jp_title}"
|
||||
if banner_image := data["bannerImage"]:
|
||||
self.header.banner_image = banner_image
|
||||
|
||||
# -----side bar-----
|
||||
|
||||
# update image
|
||||
self.side_bar.image = data["coverImage"]["extraLarge"]
|
||||
|
||||
# update alternative titles
|
||||
alternative_titles = {
|
||||
"synonyms": anilist_data_helper.format_list_data_with_comma(
|
||||
data["synonyms"]
|
||||
), # list
|
||||
"japanese": jp_title,
|
||||
"english": english_title,
|
||||
}
|
||||
self.side_bar.alternative_titles = alternative_titles
|
||||
|
||||
# update information
|
||||
information = {
|
||||
"episodes": data["episodes"],
|
||||
"status": data["status"],
|
||||
"nextAiringEpisode": anilist_data_helper.extract_next_airing_episode(
|
||||
data["nextAiringEpisode"]
|
||||
),
|
||||
"aired": f"{anilist_data_helper.format_anilist_date_object(data['startDate'])} to {anilist_data_helper.format_anilist_date_object(data['endDate'])}",
|
||||
"premiered": f"{data['season']} {data['seasonYear']}",
|
||||
"broadcast": data["format"],
|
||||
"countryOfOrigin": data["countryOfOrigin"],
|
||||
"hashtag": data["hashtag"],
|
||||
"studios": anilist_data_helper.format_list_data_with_comma(
|
||||
[studio["name"] for studio in studios if studio["isAnimationStudio"]]
|
||||
), # { "name": "Sunrise", "isAnimationStudio": true }
|
||||
"producers": anilist_data_helper.format_list_data_with_comma(
|
||||
[
|
||||
studio["name"]
|
||||
for studio in studios
|
||||
if not studio["isAnimationStudio"]
|
||||
]
|
||||
),
|
||||
"source": data["source"],
|
||||
"genres": anilist_data_helper.format_list_data_with_comma(data["genres"]),
|
||||
"duration": data["duration"],
|
||||
}
|
||||
self.side_bar.information = information
|
||||
|
||||
# update statistics
|
||||
statistics = [*[(stat["context"], stat["rank"]) for stat in data["rankings"]]]
|
||||
self.side_bar.statistics = statistics
|
||||
|
||||
# update tags
|
||||
self.side_bar.tags = [(tag["name"], tag["rank"]) for tag in data["tags"]]
|
||||
|
||||
# update external links
|
||||
|
||||
external_links = [
|
||||
("AniList", data["siteUrl"]),
|
||||
*[(site["site"], site["url"]) for site in data["externalLinks"]],
|
||||
]
|
||||
self.side_bar.external_links = external_links
|
||||
|
||||
self.rankings_bar.rankings = {
|
||||
"Popularity": data["popularity"],
|
||||
"Favourites": data["favourites"],
|
||||
"AverageScore": data["averageScore"] if data["averageScore"] else 0,
|
||||
}
|
||||
|
||||
self.anime_description.description = data["description"]
|
||||
|
||||
self.anime_characters.characters = [
|
||||
(character["node"], character["voiceActors"])
|
||||
for character in data["characters"]["edges"]
|
||||
] # list (character,actor)
|
||||
|
||||
self.anime_reviews.reviews = data["reviews"]["nodes"]
|
||||
|
||||
def stream_anime_with_custom_cmds_dialog(self, mpv=False):
|
||||
"""
|
||||
Called when user wants to stream with custom commands
|
||||
"""
|
||||
|
||||
AnimdlStreamDialog(self.data, mpv).open()
|
||||
|
||||
def open_download_anime_dialog(self):
|
||||
"""
|
||||
Opens the download anime dialog
|
||||
"""
|
||||
|
||||
DownloadAnimeDialog(self.data).open()
|
||||
def update_current_link(self, field):
|
||||
self.controller.fetch_streams(self.current_title, field.text)
|
||||
|
||||
def add_to_user_anime_list(self, *args):
|
||||
self.app.add_anime_to_user_anime_list(self.model.anime_id)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
from .animdl_stream_dialog import AnimdlStreamDialog
|
||||
from .characters import AnimeCharacters
|
||||
from .controls import Controls
|
||||
from .description import AnimeDescription
|
||||
from .download_anime_dialog import DownloadAnimeDialog
|
||||
from .header import AnimeHeader
|
||||
from .rankings_bar import RankingsBar
|
||||
from .review import AnimeReviews
|
||||
from .side_bar import AnimeSideBar
|
||||
@@ -1,63 +0,0 @@
|
||||
<StreamDialogLabel@MDLabel>:
|
||||
adaptive_height:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Label"
|
||||
role: "medium"
|
||||
bold:True
|
||||
<StreamDialogHeaderLabel@MDLabel>:
|
||||
adaptive_height:True
|
||||
halign:"center"
|
||||
max_lines:0
|
||||
shorten:False
|
||||
bold:True
|
||||
markup:True
|
||||
font_style: "Title"
|
||||
role: "medium"
|
||||
md_bg_color:self.theme_cls.secondaryContainerColor
|
||||
padding:"10dp"
|
||||
|
||||
|
||||
|
||||
<AnimdlStreamDialog>
|
||||
md_bg_color:self.theme_cls.backgroundColor
|
||||
radius:8
|
||||
size_hint:None,None
|
||||
height:"500dp"
|
||||
width:"400dp"
|
||||
MDBoxLayout:
|
||||
spacing: '10dp'
|
||||
padding:"10dp"
|
||||
orientation:"vertical"
|
||||
StreamDialogHeaderLabel:
|
||||
text:"Stream Anime"
|
||||
StreamDialogLabel:
|
||||
text:"Title"
|
||||
MDTextField:
|
||||
id:title_field
|
||||
required:True
|
||||
StreamDialogLabel:
|
||||
text:"Range"
|
||||
MDTextField:
|
||||
id:range_field
|
||||
required:True
|
||||
StreamDialogLabel:
|
||||
text:"Latest"
|
||||
MDTextField:
|
||||
id:latest_field
|
||||
required:True
|
||||
StreamDialogLabel:
|
||||
text:"Quality"
|
||||
MDTextField:
|
||||
id:quality_field
|
||||
required:True
|
||||
MDBoxLayout:
|
||||
orientation:"vertical"
|
||||
MDButton:
|
||||
pos_hint: {'center_x': 0.5}
|
||||
on_press:root.stream_anime(app)
|
||||
MDButtonIcon:
|
||||
icon:"rss"
|
||||
MDButtonText:
|
||||
text:"Stream"
|
||||
@@ -1,69 +0,0 @@
|
||||
from kivy.clock import Clock
|
||||
from kivy.uix.modalview import ModalView
|
||||
from kivymd.theming import ThemableBehavior
|
||||
from kivymd.uix.behaviors import (
|
||||
BackgroundColorBehavior,
|
||||
CommonElevationBehavior,
|
||||
StencilBehavior,
|
||||
)
|
||||
|
||||
|
||||
class AnimdlStreamDialog(
|
||||
ThemableBehavior,
|
||||
StencilBehavior,
|
||||
CommonElevationBehavior,
|
||||
BackgroundColorBehavior,
|
||||
ModalView,
|
||||
):
|
||||
"""The anime streaming dialog"""
|
||||
|
||||
def __init__(self, data, mpv, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.data = data
|
||||
self.mpv = mpv
|
||||
if title := data["title"].get("romaji"):
|
||||
self.ids.title_field.text = title
|
||||
elif title := data["title"].get("english"):
|
||||
self.ids.title_field.text = title
|
||||
|
||||
self.ids.quality_field.text = "best"
|
||||
|
||||
def _stream_anime(self, app):
|
||||
if self.mpv:
|
||||
streaming_cmds = {}
|
||||
title = self.ids.title_field.text
|
||||
streaming_cmds["title"] = title
|
||||
|
||||
episodes_range = self.ids.range_field.text
|
||||
if episodes_range:
|
||||
streaming_cmds["episodes_range"] = episodes_range
|
||||
|
||||
quality = self.ids.quality_field.text
|
||||
if quality:
|
||||
streaming_cmds["quality"] = quality
|
||||
else:
|
||||
streaming_cmds["quality"] = "best"
|
||||
|
||||
app.watch_on_animdl(streaming_cmds)
|
||||
else:
|
||||
cmds = []
|
||||
title = self.ids.title_field.text
|
||||
cmds.append(title)
|
||||
|
||||
episodes_range = self.ids.range_field.text
|
||||
if episodes_range:
|
||||
cmds = [*cmds, "-r", episodes_range]
|
||||
|
||||
latest = self.ids.latest_field.text
|
||||
if latest:
|
||||
cmds = [*cmds, "-s", latest]
|
||||
|
||||
quality = self.ids.quality_field.text
|
||||
if quality:
|
||||
cmds = [*cmds, "-q", quality]
|
||||
|
||||
app.watch_on_animdl(custom_options=cmds)
|
||||
self.dismiss()
|
||||
|
||||
def stream_anime(self, app):
|
||||
Clock.schedule_once(lambda _: self._stream_anime(app))
|
||||
@@ -1,71 +0,0 @@
|
||||
#:import get_hex_from_color kivy.utils.get_hex_from_color
|
||||
|
||||
<CharactersContainer@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
md_bg_color:self.theme_cls.surfaceContainerLowColor
|
||||
padding:"10dp"
|
||||
orientation:"vertical"
|
||||
|
||||
<CharacterText@MDLabel>:
|
||||
adaptive_height:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Body"
|
||||
role: "small"
|
||||
|
||||
<CharacterHeader@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
spacing:"10dp"
|
||||
<CharacterAvatar@FitImage>
|
||||
radius:50
|
||||
size_hint:None,None
|
||||
height:"50dp"
|
||||
width:"50dp"
|
||||
|
||||
<CharacterSecondaryContainer@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
orientation:"vertical"
|
||||
<AnimeCharacter>:
|
||||
spacing:"5dp"
|
||||
adaptive_height:True
|
||||
orientation:"vertical"
|
||||
CharacterHeader:
|
||||
padding:"10dp"
|
||||
CharacterAvatar:
|
||||
source:root.character["image"]
|
||||
CharacterText:
|
||||
text: root.character["name"]
|
||||
pos_hint:{"center_y":.5}
|
||||
|
||||
CharacterSecondaryContainer:
|
||||
spacing:"5dp"
|
||||
MDDivider:
|
||||
CharacterText:
|
||||
text: "Details"
|
||||
MDDivider:
|
||||
CharacterText:
|
||||
text:"[color={}]Gender:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.character["gender"])
|
||||
CharacterText:
|
||||
text:"[color={}]Date Of Birth:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.character["dateOfBirth"])
|
||||
CharacterText:
|
||||
text:"[color={}]Age:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.character["age"])
|
||||
CharacterText:
|
||||
text:"[color={}]Description:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.character["description"])
|
||||
max_lines:5
|
||||
CharacterText:
|
||||
text:"[color={}]Voice Actors:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.voice_actors["name"])
|
||||
MDDivider:
|
||||
|
||||
|
||||
<AnimeCharacters>:
|
||||
adaptive_height:True
|
||||
container:container
|
||||
orientation:"vertical"
|
||||
HeaderLabel:
|
||||
text:"Characters"
|
||||
halign:"left"
|
||||
CharactersContainer:
|
||||
id:container
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
from kivy.clock import Clock
|
||||
from kivy.properties import ListProperty, ObjectProperty
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
|
||||
from ....Utility.anilist_data_helper import format_anilist_date_object
|
||||
|
||||
|
||||
class AnimeCharacter(MDBoxLayout):
|
||||
"""an Anime character data"""
|
||||
|
||||
voice_actors = ObjectProperty({"name": "", "image": ""})
|
||||
character = ObjectProperty(
|
||||
{
|
||||
"name": "",
|
||||
"gender": "",
|
||||
"dateOfBirth": "",
|
||||
"image": "",
|
||||
"age": "",
|
||||
"description": "",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class AnimeCharacters(MDBoxLayout):
|
||||
"""The anime characters card"""
|
||||
|
||||
container = ObjectProperty()
|
||||
characters = ListProperty()
|
||||
|
||||
def update_characters_card(self, instance, characters):
|
||||
self.container.clear_widgets()
|
||||
for character_ in characters: # character (character,actor)
|
||||
character = character_[0]
|
||||
actors = character_[1]
|
||||
|
||||
anime_character = AnimeCharacter()
|
||||
anime_character.character = {
|
||||
"name": character["name"]["full"],
|
||||
"gender": character["gender"],
|
||||
"dateOfBirth": format_anilist_date_object(character["dateOfBirth"]),
|
||||
"image": character["image"]["medium"],
|
||||
"age": character["age"],
|
||||
"description": character["description"],
|
||||
}
|
||||
anime_character.voice_actors = {
|
||||
"name": ", ".join([actor["name"]["full"] for actor in actors])
|
||||
}
|
||||
|
||||
# anime_character.voice_actor =
|
||||
self.container.add_widget(anime_character)
|
||||
|
||||
def on_characters(self, *args):
|
||||
Clock.schedule_once(lambda _: self.update_characters_card(*args))
|
||||
@@ -1,32 +0,0 @@
|
||||
<Controls>
|
||||
adaptive_height:True
|
||||
padding:"10dp"
|
||||
spacing:"10dp"
|
||||
pos_hint: {'center_x': 0.5}
|
||||
cols:3
|
||||
MDButton:
|
||||
on_press:
|
||||
root.screen.add_to_user_anime_list()
|
||||
add_to_user_list_label.text = "Added to MyAnimeList"
|
||||
MDButtonText:
|
||||
id:add_to_user_list_label
|
||||
text:"Add to MyAnimeList"
|
||||
MDButton:
|
||||
on_press:
|
||||
if root.screen:root.screen.stream_anime_with_custom_cmds_dialog()
|
||||
MDButtonText:
|
||||
text:"Watch on Animdl"
|
||||
MDButton:
|
||||
on_press:
|
||||
if root.screen:root.screen.stream_anime_with_custom_cmds_dialog(mpv=True)
|
||||
MDButtonText:
|
||||
text:"Watch on mpv"
|
||||
MDButton:
|
||||
on_press: app.watch_on_allanime(root.screen.data["title"]["romaji"]) if root.screen.data["title"]["romaji"] else app.watch_on_allanime(root.screen.data["title"]["english"])
|
||||
MDButtonText:
|
||||
text:"Watch on AllAnime"
|
||||
MDButton:
|
||||
on_press:
|
||||
if root.screen:root.screen.open_download_anime_dialog()
|
||||
MDButtonText:
|
||||
text:"Download Anime"
|
||||
@@ -1,8 +0,0 @@
|
||||
from kivy.properties import ObjectProperty
|
||||
from kivymd.uix.gridlayout import MDGridLayout
|
||||
|
||||
|
||||
class Controls(MDGridLayout):
|
||||
"""The diferent controls available"""
|
||||
|
||||
screen = ObjectProperty()
|
||||
@@ -1,23 +0,0 @@
|
||||
<DescriptionContainer@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
md_bg_color:self.theme_cls.surfaceContainerLowColor
|
||||
padding:"10dp"
|
||||
|
||||
<DescriptionText@MDLabel>:
|
||||
adaptive_height:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Body"
|
||||
role: "small"
|
||||
<AnimeDescription>:
|
||||
orientation:"vertical"
|
||||
adaptive_height:True
|
||||
HeaderLabel:
|
||||
halign:"left"
|
||||
text:"Description"
|
||||
DescriptionContainer:
|
||||
DescriptionText:
|
||||
text:root.description
|
||||
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
from kivy.properties import StringProperty
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
|
||||
|
||||
class AnimeDescription(MDBoxLayout):
|
||||
"""The anime description"""
|
||||
|
||||
description = StringProperty()
|
||||
@@ -1,58 +0,0 @@
|
||||
<DownloadDialogLabel@MDLabel>:
|
||||
adaptive_height:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Label"
|
||||
role: "medium"
|
||||
bold:True
|
||||
<DownloadDialogHeaderLabel@MDLabel>:
|
||||
adaptive_height:True
|
||||
halign:"center"
|
||||
max_lines:0
|
||||
shorten:False
|
||||
bold:True
|
||||
markup:True
|
||||
font_style: "Title"
|
||||
role: "medium"
|
||||
md_bg_color:self.theme_cls.secondaryContainerColor
|
||||
padding:"10dp"
|
||||
|
||||
|
||||
|
||||
<DownloadAnimeDialog>
|
||||
md_bg_color:self.theme_cls.backgroundColor
|
||||
radius:8
|
||||
size_hint:None,None
|
||||
height:"500dp"
|
||||
width:"400dp"
|
||||
MDBoxLayout:
|
||||
spacing: '10dp'
|
||||
padding:"10dp"
|
||||
orientation:"vertical"
|
||||
DownloadDialogHeaderLabel:
|
||||
text:"Download Anime"
|
||||
DownloadDialogLabel:
|
||||
text:"Title"
|
||||
MDTextField:
|
||||
id:title_field
|
||||
required:True
|
||||
DownloadDialogLabel:
|
||||
text:"Range"
|
||||
MDTextField:
|
||||
id:range_field
|
||||
required:True
|
||||
DownloadDialogLabel:
|
||||
text:"Quality"
|
||||
MDTextField:
|
||||
id:quality_field
|
||||
required:True
|
||||
MDBoxLayout:
|
||||
orientation:"vertical"
|
||||
MDButton:
|
||||
pos_hint: {'center_x': 0.5}
|
||||
on_press:root.download_anime(app)
|
||||
MDButtonIcon:
|
||||
icon:"download"
|
||||
MDButtonText:
|
||||
text:"Download"
|
||||
@@ -1,41 +0,0 @@
|
||||
from kivy.uix.modalview import ModalView
|
||||
from kivymd.theming import ThemableBehavior
|
||||
from kivymd.uix.behaviors import (
|
||||
BackgroundColorBehavior,
|
||||
CommonElevationBehavior,
|
||||
StencilBehavior,
|
||||
)
|
||||
|
||||
|
||||
# from main import AniXStreamApp
|
||||
class DownloadAnimeDialog(
|
||||
ThemableBehavior,
|
||||
StencilBehavior,
|
||||
CommonElevationBehavior,
|
||||
BackgroundColorBehavior,
|
||||
ModalView,
|
||||
):
|
||||
"""The download anime dialog"""
|
||||
|
||||
def __init__(self, data, **kwargs):
|
||||
super(DownloadAnimeDialog, self).__init__(**kwargs)
|
||||
self.data = data
|
||||
self.anime_id = self.data["id"]
|
||||
if title := data["title"].get("romaji"):
|
||||
self.ids.title_field.text = title
|
||||
elif title := data["title"].get("english"):
|
||||
self.ids.title_field.text = title
|
||||
self.ids.quality_field.text = "best"
|
||||
|
||||
def download_anime(self, app):
|
||||
default_cmds = {}
|
||||
title = self.ids.title_field.text
|
||||
default_cmds["title"] = title
|
||||
if episodes_range := self.ids.range_field.text:
|
||||
default_cmds["episodes_range"] = episodes_range
|
||||
|
||||
if quality := self.ids.range_field.text:
|
||||
default_cmds["quality"] = quality
|
||||
|
||||
app.download_anime(self.anime_id, default_cmds)
|
||||
self.dismiss()
|
||||
@@ -1,20 +0,0 @@
|
||||
<AnimeHeader>:
|
||||
adaptive_height:True
|
||||
orientation: 'vertical'
|
||||
MDBoxLayout:
|
||||
adaptive_height:True
|
||||
md_bg_color:self.theme_cls.secondaryContainerColor
|
||||
MDLabel:
|
||||
text: root.titles
|
||||
adaptive_height:True
|
||||
padding:"5dp"
|
||||
bold:True
|
||||
shorten:False
|
||||
max_lines:2
|
||||
font_style:"Label"
|
||||
role:"large"
|
||||
FitImage:
|
||||
size_hint_y: None
|
||||
height: dp(250)
|
||||
source: root.banner_image if root.banner_image else app.default_banner_image
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
from kivy.properties import StringProperty
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
|
||||
|
||||
class AnimeHeader(MDBoxLayout):
|
||||
titles = StringProperty()
|
||||
banner_image = StringProperty()
|
||||
@@ -1,81 +0,0 @@
|
||||
#:set yellow [.9,.9,0,.9]
|
||||
|
||||
<RankingsLabel@MDLabel>:
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Label"
|
||||
role: "medium"
|
||||
|
||||
<RankingsHeaderLabel@MDLabel>:
|
||||
color:self.theme_cls.primaryColor
|
||||
bold:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
|
||||
|
||||
<RankingsDivider@MDDivider>:
|
||||
orientation:"vertical"
|
||||
|
||||
<RankingsBoxLayout@MDBoxLayout>:
|
||||
orientation:"vertical"
|
||||
padding:"20dp"
|
||||
<RankingsBar>:
|
||||
size_hint_y:None
|
||||
height:dp(100)
|
||||
line_color:self.theme_cls.secondaryColor
|
||||
padding:"10dp"
|
||||
RankingsBoxLayout:
|
||||
size_hint_x:.4
|
||||
RankingsHeaderLabel:
|
||||
text:"Average Score"
|
||||
MDBoxLayout:
|
||||
adaptive_width:True
|
||||
MDBoxLayout:
|
||||
adaptive_size:True
|
||||
pos_hint: {'center_y': .5}
|
||||
MDIcon:
|
||||
icon: "star"
|
||||
color:yellow
|
||||
disabled: not((root.rankings["AverageScore"]/100)*6>=1)
|
||||
MDIcon:
|
||||
color:yellow
|
||||
disabled: not(root.rankings["AverageScore"]/100*6>=2)
|
||||
icon: "star"
|
||||
MDIcon:
|
||||
color:yellow
|
||||
disabled: not(root.rankings["AverageScore"]/100*6>=3)
|
||||
icon: "star"
|
||||
MDIcon:
|
||||
color:yellow
|
||||
disabled: not(root.rankings["AverageScore"]/100*6>=4)
|
||||
icon: "star"
|
||||
MDIcon:
|
||||
color:yellow
|
||||
icon: "star"
|
||||
disabled: not(root.rankings["AverageScore"]/100*6>=5)
|
||||
MDIcon:
|
||||
color:yellow
|
||||
icon: "star"
|
||||
disabled: not(root.rankings["AverageScore"]/100*6>=6)
|
||||
RankingsLabel:
|
||||
adaptive_width:True
|
||||
text: '{}'.format(root.rankings["AverageScore"]/10)
|
||||
RankingsDivider:
|
||||
RankingsBoxLayout:
|
||||
size_hint_x:.3
|
||||
RankingsHeaderLabel:
|
||||
text:"Popularity"
|
||||
RankingsLabel:
|
||||
text: '{}'.format(root.rankings["Popularity"])
|
||||
RankingsDivider:
|
||||
RankingsBoxLayout:
|
||||
size_hint_x:.3
|
||||
RankingsHeaderLabel:
|
||||
text:"Favourites"
|
||||
RankingsLabel:
|
||||
text: '{}'.format(root.rankings["Favourites"])
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
from kivy.properties import DictProperty
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
|
||||
|
||||
class RankingsBar(MDBoxLayout):
|
||||
rankings = DictProperty(
|
||||
{
|
||||
"Popularity": 0,
|
||||
"Favourites": 0,
|
||||
"AverageScore": 0,
|
||||
}
|
||||
)
|
||||
@@ -1,50 +0,0 @@
|
||||
#:import get_hex_from_color kivy.utils.get_hex_from_color
|
||||
|
||||
|
||||
<ReviewContainer@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
md_bg_color:self.theme_cls.surfaceContainerLowColor
|
||||
padding:"10dp"
|
||||
orientation:"vertical"
|
||||
|
||||
<ReviewText@MDLabel>:
|
||||
adaptive_height:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Body"
|
||||
role: "small"
|
||||
|
||||
<ReviewHeader@MDBoxLayout>:
|
||||
adaptive_height:True
|
||||
spacing:"10dp"
|
||||
padding:"10dp"
|
||||
|
||||
<ReviewerAvatar@FitImage>
|
||||
radius:50
|
||||
size_hint:None,None
|
||||
height:"50dp"
|
||||
width:"50dp"
|
||||
|
||||
<AnimeReview>
|
||||
orientation:"vertical"
|
||||
adaptive_height:True
|
||||
ReviewHeader:
|
||||
ReviewerAvatar:
|
||||
source:root.review["avatar"]
|
||||
ReviewText:
|
||||
pos_hint: {'center_y': 0.5}
|
||||
text:root.review["username"]
|
||||
MDDivider:
|
||||
ReviewText:
|
||||
text:root.review["summary"]
|
||||
MDDivider:
|
||||
<AnimeReviews>:
|
||||
container:container
|
||||
adaptive_height:True
|
||||
orientation:"vertical"
|
||||
HeaderLabel:
|
||||
halign:"left"
|
||||
text:"reviews"
|
||||
ReviewContainer:
|
||||
id:container
|
||||
@@ -1,28 +0,0 @@
|
||||
from kivy.clock import Clock
|
||||
from kivy.properties import ListProperty, ObjectProperty
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
|
||||
|
||||
class AnimeReview(MDBoxLayout):
|
||||
review = ObjectProperty({"username": "", "avatar": "", "summary": ""})
|
||||
|
||||
|
||||
class AnimeReviews(MDBoxLayout):
|
||||
"""anime reviews"""
|
||||
|
||||
reviews = ListProperty()
|
||||
container = ObjectProperty()
|
||||
|
||||
def on_reviews(self, *args):
|
||||
Clock.schedule_once(lambda _: self.update_reviews_card(*args))
|
||||
|
||||
def update_reviews_card(self, instance, reviews):
|
||||
self.container.clear_widgets()
|
||||
for review in reviews:
|
||||
review_ = AnimeReview()
|
||||
review_.review = {
|
||||
"username": review["user"]["name"],
|
||||
"avatar": review["user"]["avatar"]["medium"],
|
||||
"summary": review["summary"],
|
||||
}
|
||||
self.container.add_widget(review_)
|
||||
@@ -1,102 +0,0 @@
|
||||
#:import get_hex_from_color kivy.utils.get_hex_from_color
|
||||
|
||||
<FitBoxLayout@MDBoxLayout>:
|
||||
size_hint_y:None
|
||||
height:self.minimum_height
|
||||
padding:"10dp"
|
||||
spacing:"10dp"
|
||||
orientation: 'vertical'
|
||||
pos_hint: {'center_x': 0.5}
|
||||
<SideBarLabel>:
|
||||
adaptive_height:True
|
||||
max_lines:0
|
||||
shorten:False
|
||||
markup:True
|
||||
font_style: "Label"
|
||||
role: "medium"
|
||||
<HeaderLabel>:
|
||||
adaptive_height:True
|
||||
md_bg_color:self.theme_cls.secondaryContainerColor
|
||||
MDLabel:
|
||||
text:root.text
|
||||
adaptive_height:True
|
||||
halign:root.halign
|
||||
max_lines:0
|
||||
shorten:False
|
||||
bold:True
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
padding:"10dp"
|
||||
|
||||
<AnimeSideBar>:
|
||||
size_hint_x: None
|
||||
width: dp(300)
|
||||
orientation: 'vertical'
|
||||
line_color:self.theme_cls.secondaryColor
|
||||
statistics_container:statistics_container
|
||||
tags_container:tags_container
|
||||
external_links_container:external_links_container
|
||||
FitBoxLayout:
|
||||
FitImage:
|
||||
source:root.image
|
||||
size_hint:None,None
|
||||
height:dp(250)
|
||||
width:dp(200)
|
||||
pos_hint: {'center_x': 0.5}
|
||||
MDButton:
|
||||
pos_hint: {'center_x': 0.5}
|
||||
on_press:
|
||||
if root.screen:root.screen.stream_anime_with_custom_cmds_dialog(mpv=True)
|
||||
MDButtonText:
|
||||
text:"Watch with mpv"
|
||||
FitBoxLayout:
|
||||
HeaderLabel:
|
||||
text:"Alternative Titles"
|
||||
SideBarLabel:
|
||||
text: "[color={}]Synonyms:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.alternative_titles["synonyms"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]English:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.alternative_titles["english"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Japanese:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.alternative_titles["japanese"])
|
||||
FitBoxLayout:
|
||||
HeaderLabel:
|
||||
text:"Information"
|
||||
SideBarLabel:
|
||||
text: "[color={}]Episodes:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["episodes"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Status:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["status"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Next Airing Episode:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["nextAiringEpisode"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Aired:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["aired"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Premiered:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["premiered"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Broadcast:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["broadcast"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Country Of Origin:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["countryOfOrigin"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Hashtag:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["hashtag"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Studios:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["studios"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Producers:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["producers"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Source:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["source"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Genres:[/color] {}".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["genres"])
|
||||
SideBarLabel:
|
||||
text: "[color={}]Duration:[/color] {} minutes".format(get_hex_from_color(self.theme_cls.primaryColor),root.information["duration"])
|
||||
FitBoxLayout:
|
||||
id:statistics_container
|
||||
HeaderLabel:
|
||||
text:"Rankings"
|
||||
FitBoxLayout:
|
||||
id:tags_container
|
||||
HeaderLabel:
|
||||
text:"Tags"
|
||||
FitBoxLayout:
|
||||
id:external_links_container
|
||||
HeaderLabel:
|
||||
text:"External Links"
|
||||
BoxLayout:
|
||||
@@ -1,97 +0,0 @@
|
||||
from kivy.factory import Factory
|
||||
from kivy.properties import DictProperty, ListProperty, ObjectProperty, StringProperty
|
||||
from kivy.utils import get_hex_from_color
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.label import MDLabel
|
||||
|
||||
|
||||
class HeaderLabel(MDBoxLayout):
|
||||
text = StringProperty()
|
||||
halign = StringProperty("center")
|
||||
|
||||
|
||||
Factory.register("HeaderLabel", HeaderLabel)
|
||||
|
||||
|
||||
class SideBarLabel(MDLabel):
|
||||
pass
|
||||
|
||||
|
||||
# TODO:Switch to using the kivy_markup_module
|
||||
class AnimeSideBar(MDBoxLayout):
|
||||
screen = ObjectProperty()
|
||||
image = StringProperty()
|
||||
alternative_titles = DictProperty(
|
||||
{
|
||||
"synonyms": "",
|
||||
"english": "",
|
||||
"japanese": "",
|
||||
}
|
||||
)
|
||||
information = DictProperty(
|
||||
{
|
||||
"episodes": "",
|
||||
"status": "",
|
||||
"aired": "",
|
||||
"nextAiringEpisode": "",
|
||||
"premiered": "",
|
||||
"broadcast": "",
|
||||
"countryOfOrigin": "",
|
||||
"hashtag": "",
|
||||
"studios": "", # { "name": "Sunrise", "isAnimationStudio": true }
|
||||
"source": "",
|
||||
"genres": "",
|
||||
"duration": "",
|
||||
"producers": "",
|
||||
}
|
||||
)
|
||||
statistics = ListProperty()
|
||||
statistics_container = ObjectProperty()
|
||||
external_links = ListProperty()
|
||||
external_links_container = ObjectProperty()
|
||||
tags = ListProperty()
|
||||
tags_container = ObjectProperty()
|
||||
|
||||
def on_statistics(self, instance, value):
|
||||
self.statistics_container.clear_widgets()
|
||||
header = HeaderLabel()
|
||||
header.text = "Rankings"
|
||||
self.statistics_container.add_widget(header)
|
||||
for stat in value:
|
||||
# stat (rank,context)
|
||||
label = SideBarLabel()
|
||||
label.text = "[color={}]{}:[/color] {}".format(
|
||||
get_hex_from_color(label.theme_cls.primaryColor),
|
||||
stat[0].capitalize(),
|
||||
f"{stat[1]}",
|
||||
)
|
||||
self.statistics_container.add_widget(label)
|
||||
|
||||
def on_tags(self, instance, value):
|
||||
self.tags_container.clear_widgets()
|
||||
header = HeaderLabel()
|
||||
header.text = "Tags"
|
||||
self.tags_container.add_widget(header)
|
||||
for tag in value:
|
||||
label = SideBarLabel()
|
||||
label.text = "[color={}]{}:[/color] {}".format(
|
||||
get_hex_from_color(label.theme_cls.primaryColor),
|
||||
tag[0].capitalize(),
|
||||
f"{tag[1]} %",
|
||||
)
|
||||
self.tags_container.add_widget(label)
|
||||
|
||||
def on_external_links(self, instance, value):
|
||||
self.external_links_container.clear_widgets()
|
||||
header = HeaderLabel()
|
||||
header.text = "External Links"
|
||||
self.external_links_container.add_widget(header)
|
||||
for site in value:
|
||||
# stat (rank,context)
|
||||
label = SideBarLabel()
|
||||
label.text = "[color={}]{}:[/color] {}".format(
|
||||
get_hex_from_color(label.theme_cls.primaryColor),
|
||||
site[0].capitalize(),
|
||||
site[1],
|
||||
)
|
||||
self.external_links_container.add_widget(label)
|
||||
@@ -30,6 +30,11 @@ class CommonNavigationRailItem(MDNavigationRailItem):
|
||||
text = StringProperty()
|
||||
|
||||
|
||||
class HeaderLabel(MDBoxLayout):
|
||||
text = StringProperty()
|
||||
halign = StringProperty("left")
|
||||
|
||||
|
||||
class BaseScreenView(MDScreen, Observer):
|
||||
"""
|
||||
A base class that implements a visual representation of the model data.
|
||||
|
||||
@@ -1,3 +1,19 @@
|
||||
<MDLabel>:
|
||||
allow_copy:True
|
||||
allow_selection:True
|
||||
allow_selection:True
|
||||
|
||||
<HeaderLabel>:
|
||||
adaptive_height:True
|
||||
md_bg_color:self.theme_cls.secondaryContainerColor
|
||||
MDLabel:
|
||||
text:root.text
|
||||
adaptive_height:True
|
||||
halign:root.halign
|
||||
max_lines:0
|
||||
shorten:False
|
||||
bold:True
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
padding:"10dp"
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
icon: "play-circle"
|
||||
on_press:
|
||||
root.dismiss()
|
||||
app.show_anime_screen(root.caller.anime_id,root.caller.screen.name)
|
||||
app.show_anime_screen(root.caller.anime_id,root.caller.title,root.caller.screen.name)
|
||||
TooltipMDIconButton:
|
||||
tooltip_text:"Add to your anime list"
|
||||
icon: "plus-circle" if not(root.caller.is_in_my_list) else "check-circle"
|
||||
|
||||
@@ -244,9 +244,9 @@ class AniXStreamApp(MDApp):
|
||||
updated_list.append(id)
|
||||
user_data_helper.get_user_downloads()
|
||||
|
||||
def show_anime_screen(self, id: int, caller_screen_name: str):
|
||||
def show_anime_screen(self, id: int, title, caller_screen_name: str):
|
||||
self.manager_screens.current = "anime screen"
|
||||
self.anime_screen.controller.update_anime_view(id, caller_screen_name)
|
||||
self.anime_screen.controller.update_anime_view(id, title, caller_screen_name)
|
||||
|
||||
def download_anime_complete(
|
||||
self, successful_downloads: list, failed_downloads: list, anime_title: str
|
||||
|
||||
@@ -196,15 +196,15 @@ class AllAnimeAPI:
|
||||
if resp.status_code == 200:
|
||||
match embed["sourceName"]:
|
||||
case "Luf-mp4":
|
||||
return "gogoanime", resp.json()
|
||||
yield "gogoanime", resp.json()
|
||||
case "Kir":
|
||||
return "wetransfer", resp.json()
|
||||
yield "wetransfer", resp.json()
|
||||
case "S-mp4":
|
||||
return "sharepoint", resp.json()
|
||||
yield "sharepoint", resp.json()
|
||||
case "Sak":
|
||||
return "dropbox", resp.json()
|
||||
yield "dropbox", resp.json()
|
||||
case _:
|
||||
return "Unknown", resp.json()
|
||||
yield "Unknown", resp.json()
|
||||
else:
|
||||
return None
|
||||
|
||||
@@ -247,6 +247,7 @@ if __name__ == "__main__":
|
||||
search_results = anime_provider.search_for_anime(
|
||||
anime, translation_type=translation.strip()
|
||||
)
|
||||
print(search_results)
|
||||
if not search_results:
|
||||
raise Exception("No results found")
|
||||
|
||||
@@ -259,7 +260,7 @@ if __name__ == "__main__":
|
||||
|
||||
anime_result = list(filter(lambda x: x["name"] == anime, search_results))[0]
|
||||
anime_data = anime_provider.get_anime(anime_result["_id"])
|
||||
|
||||
print(anime_data)
|
||||
if anime_data is None:
|
||||
raise Exception("Anime not found")
|
||||
availableEpisodesDetail = anime_data["show"]["availableEpisodesDetail"]
|
||||
@@ -279,11 +280,15 @@ if __name__ == "__main__":
|
||||
raise Exception("Episode not found")
|
||||
|
||||
episode_streams = anime_provider.get_episode_streams(episode_data)
|
||||
|
||||
if not episode_streams:
|
||||
raise Exception("No streams found")
|
||||
stream_links = [stream["link"] for stream in episode_streams[1]["links"]]
|
||||
stream_link = run_fzf([*stream_links, "quit"])
|
||||
episode_streams = list(episode_streams)
|
||||
print(episode_streams)
|
||||
|
||||
stream_links = [stream["link"] for stream in episode_streams[2][1]["links"]]
|
||||
stream_link = run_fzf([*stream_links, "quit"])
|
||||
print(stream_link)
|
||||
if stream_link == "quit":
|
||||
print("Have a nice day")
|
||||
sys.exit()
|
||||
|
||||
Reference in New Issue
Block a user