mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-12 07:40:41 -08:00
added custom streaming features plus created the rest of the views with basic template
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -166,4 +166,10 @@ cython_debug/
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
.idea/
|
||||
app/anixstream.ini
|
||||
app/settings.json
|
||||
app/user_data.json
|
||||
app/View/SearchScreen/.search_screen.py.un~
|
||||
app/View/SearchScreen/search_screen.py~
|
||||
app/user_data.json
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from .home_screen import HomeScreenController
|
||||
from .search_screen import SearchScreenController
|
||||
from .my_list_screen import MyListScreenController
|
||||
from .anime_screen import AnimeScreenController
|
||||
from .anime_screen import AnimeScreenController
|
||||
from .downloads_screen import DownloadsScreenController
|
||||
from .help_screen import HelpScreenController
|
||||
from .crashlog_screen import CrashLogScreenController
|
||||
15
app/Controller/crashlog_screen.py
Normal file
15
app/Controller/crashlog_screen.py
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
from inspect import isgenerator
|
||||
from View import CrashLogScreenView
|
||||
from Model import CrashLogScreenModel
|
||||
from View.components import MediaCardsContainer
|
||||
from Utility import show_notification
|
||||
from kivy.clock import Clock
|
||||
class CrashLogScreenController:
|
||||
def __init__(self, model:CrashLogScreenModel):
|
||||
self.model = model
|
||||
self.view = CrashLogScreenView(controller=self, model=self.model)
|
||||
# self.update_anime_view()
|
||||
|
||||
def get_view(self) -> CrashLogScreenView:
|
||||
return self.view
|
||||
15
app/Controller/downloads_screen.py
Normal file
15
app/Controller/downloads_screen.py
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
from inspect import isgenerator
|
||||
from View import DownloadsScreenView
|
||||
from Model import DownloadsScreenModel
|
||||
from View.components import MediaCardsContainer
|
||||
from Utility import show_notification
|
||||
from kivy.clock import Clock
|
||||
class DownloadsScreenController:
|
||||
def __init__(self, model:DownloadsScreenModel):
|
||||
self.model = model
|
||||
self.view = DownloadsScreenView(controller=self, model=self.model)
|
||||
# self.update_anime_view()
|
||||
|
||||
def get_view(self) -> DownloadsScreenView:
|
||||
return self.view
|
||||
15
app/Controller/help_screen.py
Normal file
15
app/Controller/help_screen.py
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
from inspect import isgenerator
|
||||
from View import HelpScreenView
|
||||
from Model import HelpScreenModel
|
||||
from View.components import MediaCardsContainer
|
||||
from Utility import show_notification
|
||||
from kivy.clock import Clock
|
||||
class HelpScreenController:
|
||||
def __init__(self, model:HelpScreenModel):
|
||||
self.model = model
|
||||
self.view = HelpScreenView(controller=self, model=self.model)
|
||||
# self.update_anime_view()
|
||||
|
||||
def get_view(self) -> HelpScreenView:
|
||||
return self.view
|
||||
@@ -18,7 +18,8 @@ class HomeScreenController:
|
||||
def __init__(self, model:HomeScreenModel):
|
||||
self.model = model # Model.main_screen.MainScreenModel
|
||||
self.view = HomeScreenView(controller=self, model=self.model)
|
||||
Clock.schedule_once(lambda _:self.populate_home_screen())
|
||||
if self.view.app.config.get("Preferences","is_startup_anime_enable")=="1":
|
||||
Clock.schedule_once(lambda _:self.populate_home_screen())
|
||||
def get_view(self) -> HomeScreenView:
|
||||
return self.view
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from .home_screen import HomeScreenModel
|
||||
from .search_screen import SearchScreenModel
|
||||
from .my_list_screen import MyListScreenModel
|
||||
from .anime_screen import AnimeScreenModel
|
||||
from .anime_screen import AnimeScreenModel
|
||||
from .crashlog_screen import CrashLogScreenModel
|
||||
from .help_screen import HelpScreenModel
|
||||
from .download_screen import DownloadsScreenModel
|
||||
7
app/Model/crashlog_screen.py
Normal file
7
app/Model/crashlog_screen.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from Model.base_model import BaseScreenModel
|
||||
|
||||
|
||||
class CrashLogScreenModel(BaseScreenModel):
|
||||
"""
|
||||
Handles the crashlog screen logic
|
||||
"""
|
||||
7
app/Model/download_screen.py
Normal file
7
app/Model/download_screen.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from Model.base_model import BaseScreenModel
|
||||
|
||||
|
||||
class DownloadsScreenModel(BaseScreenModel):
|
||||
"""
|
||||
Handles the download screen logic
|
||||
"""
|
||||
7
app/Model/help_screen.py
Normal file
7
app/Model/help_screen.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from Model.base_model import BaseScreenModel
|
||||
|
||||
|
||||
class HelpScreenModel(BaseScreenModel):
|
||||
"""
|
||||
Handles the help screen logic
|
||||
"""
|
||||
@@ -0,0 +1 @@
|
||||
from .components.animdl_stream_dialog import AnimdlStreamDialog
|
||||
@@ -34,6 +34,7 @@
|
||||
height: self.minimum_height
|
||||
AnimeSideBar:
|
||||
id:side_bar
|
||||
screen:root
|
||||
size_hint_y:None
|
||||
height:max(self.parent.height,self.minimum_height)
|
||||
|
||||
@@ -45,6 +46,7 @@
|
||||
RankingsBar:
|
||||
id:rankings_bar
|
||||
Controls:
|
||||
screen:root
|
||||
MDBoxLayout:
|
||||
adaptive_height:True
|
||||
padding:"20dp"
|
||||
|
||||
@@ -6,8 +6,9 @@ from kivymd.uix.label import MDLabel
|
||||
from kivy.utils import QueryDict,get_hex_from_color
|
||||
from collections import defaultdict
|
||||
|
||||
from . import AnimdlStreamDialog
|
||||
|
||||
|
||||
# TODO:move the rest of the classes to their own files
|
||||
|
||||
class RankingsBar(MDBoxLayout):
|
||||
rankings = DictProperty(
|
||||
@@ -22,6 +23,7 @@ class RankingsBar(MDBoxLayout):
|
||||
class AnimeDescription(MDBoxLayout):
|
||||
description = StringProperty()
|
||||
|
||||
|
||||
class AnimeCharacter(MDBoxLayout):
|
||||
voice_actors = ObjectProperty({
|
||||
"name":"",
|
||||
@@ -36,6 +38,7 @@ class AnimeCharacter(MDBoxLayout):
|
||||
"description":""
|
||||
})
|
||||
|
||||
|
||||
class AnimeCharacters(MDBoxLayout):
|
||||
container = ObjectProperty()
|
||||
characters = ListProperty()
|
||||
@@ -62,6 +65,7 @@ class AnimeCharacters(MDBoxLayout):
|
||||
# anime_character.voice_actor =
|
||||
self.container.add_widget(anime_character)
|
||||
|
||||
|
||||
class AnimeReview(MDBoxLayout):
|
||||
review = ObjectProperty({
|
||||
"username":"",
|
||||
@@ -69,6 +73,7 @@ class AnimeReview(MDBoxLayout):
|
||||
"summary":""
|
||||
})
|
||||
|
||||
|
||||
class AnimeReviews(MDBoxLayout):
|
||||
reviews = ListProperty()
|
||||
container = ObjectProperty()
|
||||
@@ -83,16 +88,22 @@ class AnimeReviews(MDBoxLayout):
|
||||
}
|
||||
self.container.add_widget(review_)
|
||||
|
||||
|
||||
class AnimeHeader(MDBoxLayout):
|
||||
titles = StringProperty()
|
||||
banner_image = StringProperty()
|
||||
|
||||
|
||||
class SideBarLabel(MDLabel):
|
||||
pass
|
||||
|
||||
|
||||
class SideBarHeaderLabel(MDLabel):
|
||||
pass
|
||||
|
||||
|
||||
class AnimeSideBar(MDBoxLayout):
|
||||
screen = ObjectProperty()
|
||||
image = StringProperty()
|
||||
alternative_titles = DictProperty({
|
||||
"synonyms":"",
|
||||
@@ -163,6 +174,10 @@ class AnimeSideBar(MDBoxLayout):
|
||||
site[1])
|
||||
self.external_links_container.add_widget(label)
|
||||
|
||||
class Controls(MDBoxLayout):
|
||||
screen = ObjectProperty()
|
||||
|
||||
|
||||
class AnimeScreenView(BaseScreenView):
|
||||
header:AnimeHeader = ObjectProperty()
|
||||
side_bar:AnimeSideBar = ObjectProperty()
|
||||
@@ -170,7 +185,7 @@ class AnimeScreenView(BaseScreenView):
|
||||
anime_description:AnimeDescription = ObjectProperty()
|
||||
anime_characters:AnimeCharacters = ObjectProperty()
|
||||
anime_reviews:AnimeReviews = ObjectProperty()
|
||||
|
||||
data = DictProperty()
|
||||
def model_is_changed(self) -> None:
|
||||
"""
|
||||
Called whenever any change has occurred in the data model.
|
||||
@@ -179,6 +194,7 @@ class AnimeScreenView(BaseScreenView):
|
||||
"""
|
||||
|
||||
def update_layout(self,data):
|
||||
self.data = data
|
||||
# uitlity functions
|
||||
format_date = lambda date_: f"{date_['day']}/{date_['month']}/{date_['year']}" if date_ else ""
|
||||
format_list_with_comma = lambda list_: ", ".join(list_) if list_ else ""
|
||||
@@ -264,4 +280,10 @@ class AnimeScreenView(BaseScreenView):
|
||||
self.anime_reviews.reviews = data["reviews"]["nodes"]
|
||||
|
||||
# for r in data["recommendation"]["nodes"]:
|
||||
# r["mediaRecommendation"]
|
||||
# r["mediaRecommendation"]
|
||||
|
||||
def stream_anime_with_custom_cmds_dialog(self):
|
||||
"""
|
||||
Called when user wants to stream with custom commands
|
||||
"""
|
||||
AnimdlStreamDialog(self.data).open()
|
||||
63
app/View/AnimeScreen/components/animdl_stream_dialog.kv
Normal file
63
app/View/AnimeScreen/components/animdl_stream_dialog.kv
Normal file
@@ -0,0 +1,63 @@
|
||||
<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 on Animdl"
|
||||
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"
|
||||
34
app/View/AnimeScreen/components/animdl_stream_dialog.py
Normal file
34
app/View/AnimeScreen/components/animdl_stream_dialog.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from kivy.uix.modalview import ModalView
|
||||
from kivymd.uix.behaviors import StencilBehavior,CommonElevationBehavior,BackgroundColorBehavior
|
||||
from kivymd.theming import ThemableBehavior
|
||||
# from main import AniXStreamApp
|
||||
class AnimdlStreamDialog(ThemableBehavior,StencilBehavior,CommonElevationBehavior,BackgroundColorBehavior,ModalView):
|
||||
def __init__(self,data,**kwargs):
|
||||
super(AnimdlStreamDialog,self).__init__(**kwargs)
|
||||
self.data = data
|
||||
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):
|
||||
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]
|
||||
|
||||
# print(title,episodes_range,latest,quality)
|
||||
print(cmds)
|
||||
app.watch_on_animdl(custom_options = cmds)
|
||||
@@ -1,4 +1,4 @@
|
||||
<Controls@MDBoxLayout>
|
||||
<Controls>
|
||||
adaptive_height:True
|
||||
padding:"10dp"
|
||||
spacing:"10dp"
|
||||
@@ -8,10 +8,11 @@
|
||||
MDButtonText:
|
||||
text:"Add to MyList"
|
||||
MDButton:
|
||||
on_press: print("presed")
|
||||
on_press:
|
||||
if root.screen:root.screen.stream_anime_with_custom_cmds_dialog()
|
||||
MDButtonText:
|
||||
text:"Watch on Animdl"
|
||||
MDButton:
|
||||
on_press: print("presed")
|
||||
on_press: app.watch_on_allanime(root.screen.data["title"]["romaji"])
|
||||
MDButtonText:
|
||||
text:"Watch on AllAnime"
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
width:dp(200)
|
||||
pos_hint: {'center_x': 0.5}
|
||||
MDButton:
|
||||
on_press:app.watch_on_animdl(root.alternative_titles)
|
||||
on_press:
|
||||
root.screen.stream_anime_with_custom_cmds_dialog()
|
||||
pos_hint: {'center_x': 0.5}
|
||||
|
||||
MDButtonText:
|
||||
|
||||
18
app/View/CrashLogScreen/crashlog_screen.kv
Normal file
18
app/View/CrashLogScreen/crashlog_screen.kv
Normal file
@@ -0,0 +1,18 @@
|
||||
#:import get_color_from_hex kivy.utils.get_color_from_hex
|
||||
#:import StringProperty kivy.properties.StringProperty
|
||||
|
||||
<CrashLogScreenView>
|
||||
md_bg_color: self.theme_cls.backgroundColor
|
||||
# main_container:main_container
|
||||
MDBoxLayout:
|
||||
NavRail:
|
||||
screen:root
|
||||
MDAnchorLayout:
|
||||
anchor_y: 'top'
|
||||
padding:"10dp"
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
SearchBar:
|
||||
|
||||
MDLabel:
|
||||
text:"Crash Log"
|
||||
12
app/View/CrashLogScreen/crashlog_screen.py
Normal file
12
app/View/CrashLogScreen/crashlog_screen.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from kivy.properties import ObjectProperty
|
||||
from View.base_screen import BaseScreenView
|
||||
|
||||
|
||||
class CrashLogScreenView(BaseScreenView):
|
||||
main_container = ObjectProperty()
|
||||
def model_is_changed(self) -> None:
|
||||
"""
|
||||
Called whenever any change has occurred in the data model.
|
||||
The view in this method tracks these changes and updates the UI
|
||||
according to these changes.
|
||||
"""
|
||||
0
app/View/DownloadsScreen/components/status_bar.kv
Normal file
0
app/View/DownloadsScreen/components/status_bar.kv
Normal file
18
app/View/DownloadsScreen/download_screen.kv
Normal file
18
app/View/DownloadsScreen/download_screen.kv
Normal file
@@ -0,0 +1,18 @@
|
||||
#:import get_color_from_hex kivy.utils.get_color_from_hex
|
||||
#:import StringProperty kivy.properties.StringProperty
|
||||
|
||||
<DownloadsScreenView>
|
||||
md_bg_color: self.theme_cls.backgroundColor
|
||||
# main_container:main_container
|
||||
MDBoxLayout:
|
||||
NavRail:
|
||||
screen:root
|
||||
MDAnchorLayout:
|
||||
anchor_y: 'top'
|
||||
padding:"10dp"
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
SearchBar:
|
||||
|
||||
MDLabel:
|
||||
text:"Downloads"
|
||||
16
app/View/DownloadsScreen/download_screen.py
Normal file
16
app/View/DownloadsScreen/download_screen.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from kivy.properties import ObjectProperty
|
||||
from View.base_screen import BaseScreenView
|
||||
from kivy.uix.modalview import ModalView
|
||||
|
||||
class DownloadAnimePopup(ModalView):
|
||||
pass
|
||||
|
||||
class DownloadsScreenView(BaseScreenView):
|
||||
main_container = ObjectProperty()
|
||||
def model_is_changed(self) -> None:
|
||||
"""
|
||||
Called whenever any change has occurred in the data model.
|
||||
The view in this method tracks these changes and updates the UI
|
||||
according to these changes.
|
||||
"""
|
||||
|
||||
18
app/View/HelpScreen/help_screen.kv
Normal file
18
app/View/HelpScreen/help_screen.kv
Normal file
@@ -0,0 +1,18 @@
|
||||
#:import get_color_from_hex kivy.utils.get_color_from_hex
|
||||
#:import StringProperty kivy.properties.StringProperty
|
||||
|
||||
<HelpScreenView>
|
||||
md_bg_color: self.theme_cls.backgroundColor
|
||||
# main_container:main_container
|
||||
MDBoxLayout:
|
||||
NavRail:
|
||||
screen:root
|
||||
MDAnchorLayout:
|
||||
anchor_y: 'top'
|
||||
padding:"10dp"
|
||||
MDBoxLayout:
|
||||
orientation: 'vertical'
|
||||
SearchBar:
|
||||
|
||||
MDLabel:
|
||||
text:"Help Screen"
|
||||
13
app/View/HelpScreen/help_screen.py
Normal file
13
app/View/HelpScreen/help_screen.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from kivy.properties import ObjectProperty
|
||||
from View.base_screen import BaseScreenView
|
||||
|
||||
|
||||
class HelpScreenView(BaseScreenView):
|
||||
main_container = ObjectProperty()
|
||||
def model_is_changed(self) -> None:
|
||||
"""
|
||||
Called whenever any change has occurred in the data model.
|
||||
The view in this method tracks these changes and updates the UI
|
||||
according to these changes.
|
||||
"""
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
# screens
|
||||
from .HomeScreen.home_screen import HomeScreenView
|
||||
from .SearchScreen.search_screen import SearchScreenView
|
||||
from .MylistScreen.my_list_screen import MyListScreenView
|
||||
from .AnimeScreen.anime_screen import AnimeScreenView
|
||||
from .AnimeScreen.anime_screen import AnimeScreenView
|
||||
from .CrashLogScreen.crashlog_screen import CrashLogScreenView
|
||||
from .DownloadsScreen.download_screen import DownloadsScreenView
|
||||
from .HelpScreen.help_screen import HelpScreenView
|
||||
|
||||
# others
|
||||
from .components.animdl_dialog.animdl_dialog import AnimdlDialogPopup
|
||||
from .DownloadsScreen.download_screen import DownloadAnimePopup
|
||||
0
app/View/components/animdl_dialog/animdl_dialog.kv
Normal file
0
app/View/components/animdl_dialog/animdl_dialog.kv
Normal file
4
app/View/components/animdl_dialog/animdl_dialog.py
Normal file
4
app/View/components/animdl_dialog/animdl_dialog.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from kivy.uix.modalview import ModalView
|
||||
|
||||
class AnimdlDialogPopup(ModalView):
|
||||
pass
|
||||
@@ -1,3 +1,3 @@
|
||||
<MDLabel>:
|
||||
allow_copy:True
|
||||
allow_selection:True
|
||||
# <MDLabel>:
|
||||
# allow_copy:True
|
||||
# allow_selection:True
|
||||
@@ -30,14 +30,21 @@
|
||||
on_press:
|
||||
root.screen.manager_screens.current = "my list screen"
|
||||
CommonNavigationRailItem:
|
||||
icon: "library"
|
||||
text: "Library"
|
||||
icon: "download-circle"
|
||||
text: "Downloads"
|
||||
on_press:
|
||||
root.screen.manager_screens.current = "anime screen"
|
||||
root.screen.manager_screens.current = "downloads screen"
|
||||
CommonNavigationRailItem:
|
||||
icon: "cog"
|
||||
text: "settings"
|
||||
on_press:app.open_settings()
|
||||
CommonNavigationRailItem:
|
||||
icon: "help-circle"
|
||||
text: "Help"
|
||||
on_press:
|
||||
root.screen.manager_screens.current = "help screen"
|
||||
CommonNavigationRailItem:
|
||||
icon: "bug"
|
||||
text: "debug"
|
||||
on_press:
|
||||
root.screen.manager_screens.current = "crashlog screen"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from Controller import SearchScreenController,HomeScreenController,MyListScreenController,AnimeScreenController
|
||||
from Model import HomeScreenModel,SearchScreenModel,MyListScreenModel,AnimeScreenModel
|
||||
from Controller import (SearchScreenController,HomeScreenController,MyListScreenController,AnimeScreenController,DownloadsScreenController,HelpScreenController,CrashLogScreenController)
|
||||
from Model import (HomeScreenModel,SearchScreenModel,MyListScreenModel,AnimeScreenModel,DownloadsScreenModel,HelpScreenModel,CrashLogScreenModel)
|
||||
|
||||
|
||||
screens = {
|
||||
@@ -19,4 +19,16 @@ screens = {
|
||||
"model": AnimeScreenModel,
|
||||
"controller": AnimeScreenController,
|
||||
},
|
||||
"crashlog screen": {
|
||||
"model": CrashLogScreenModel,
|
||||
"controller": CrashLogScreenController,
|
||||
},
|
||||
"downloads screen": {
|
||||
"model": DownloadsScreenModel,
|
||||
"controller": DownloadsScreenController,
|
||||
},
|
||||
"help screen": {
|
||||
"model": HelpScreenModel,
|
||||
"controller": HelpScreenController,
|
||||
},
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
3.12
|
||||
Binary file not shown.
@@ -19,6 +19,21 @@ class AnimdlApi:
|
||||
else:
|
||||
return run([py_path,"-m", "animdl", *cmds])
|
||||
|
||||
@classmethod
|
||||
def run_custom_command(cls,*cmds:tuple[str])->Popen:
|
||||
"""
|
||||
Runs an AnimDl custom command with the full power of animdl and returns a subprocess(popen) for full control
|
||||
"""
|
||||
|
||||
# TODO: parse the commands
|
||||
parsed_cmds = list(cmds)
|
||||
|
||||
if py_path:=shutil.which("python"):
|
||||
base_cmds = [py_path,"-m","animdl"]
|
||||
child_process = Popen([*base_cmds,*parsed_cmds])
|
||||
return child_process
|
||||
|
||||
|
||||
@classmethod
|
||||
def stream_anime_by_title(cls,title,episodes_range=None):
|
||||
anime = cls.get_anime_url_by_title(title)
|
||||
@@ -183,7 +198,7 @@ class AnimdlApi:
|
||||
possible_animes = cls.output_parser(result)
|
||||
if possible_animes:
|
||||
anime = max(possible_animes.items(),key=lambda anime_item:cls.get_anime_match(anime_item,title))
|
||||
return anime # {"title","anime url"}
|
||||
return anime # ("title","anime url")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
|
||||
106
app/main.py
106
app/main.py
@@ -13,6 +13,11 @@ import json
|
||||
from queue import Queue
|
||||
from threading import Thread
|
||||
import plyer
|
||||
# plyer.facades.StoragePath.get_application_dir
|
||||
# plyer.facades.StoragePath.get_downloads_dir
|
||||
# plyer.facades.StoragePath.get_videos_dir()
|
||||
# plyer.facades.StoragePath.
|
||||
# plyer.facades.StoragePath.get_application_dir
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from kivy.uix.settings import SettingsWithSidebar,Settings
|
||||
@@ -22,9 +27,11 @@ from kivy.storage.jsonstore import JsonStore
|
||||
from datetime import date,datetime
|
||||
from subprocess import Popen
|
||||
from View.screens import screens
|
||||
|
||||
from View import DownloadAnimePopup,AnimdlDialogPopup
|
||||
import time
|
||||
from Utility import themes_available
|
||||
|
||||
import webbrowser
|
||||
from Utility import themes_available,show_notification
|
||||
|
||||
user_data = JsonStore("user_data.json")
|
||||
today = date.today()
|
||||
@@ -43,13 +50,18 @@ elif not( yt_cache.get("yt_stream_links").get(f"{links_cache_name}")):
|
||||
|
||||
class AniXStreamApp(MDApp):
|
||||
queue = Queue()
|
||||
downloads_queue = Queue()
|
||||
animdl_streaming_subprocess:Popen|None = None
|
||||
def worker(self,queue:Queue):
|
||||
while True:
|
||||
task = queue.get() # task should be a function
|
||||
task()
|
||||
self.queue.task_done()
|
||||
|
||||
def downloads_worker(self,queue:Queue):
|
||||
while True:
|
||||
download_task = queue.get() # task should be a function
|
||||
download_task()
|
||||
self.queue.task_done()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
@@ -64,6 +76,11 @@ class AniXStreamApp(MDApp):
|
||||
self.worker_thread.daemon = True
|
||||
self.worker_thread.start()
|
||||
|
||||
# initialize downloads worker
|
||||
self.downloads_worker_thread = Thread(target=self.downloads_worker,args=(self.downloads_queue,))
|
||||
self.downloads_worker_thread.daemon = True
|
||||
self.downloads_worker_thread.start()
|
||||
|
||||
def build(self) -> ScreenManager:
|
||||
self.settings_cls = SettingsWithSidebar
|
||||
self.generate_application_screens()
|
||||
@@ -92,8 +109,10 @@ class AniXStreamApp(MDApp):
|
||||
config.setdefaults('Preferences', {
|
||||
'theme_color': 'Cyan',
|
||||
"theme_style": "Dark",
|
||||
"downloads_dir":"."
|
||||
"downloads_dir": plyer.storagepath.get_videos_dir() if plyer.storagepath.get_videos_dir() else ".",
|
||||
"is_startup_anime_enable":False
|
||||
})
|
||||
print(self.config.get("Preferences","is_startup_anime_enable"))
|
||||
|
||||
def build_settings(self,settings:Settings):
|
||||
settings.add_json_panel("Settings",self.config,"settings.json")
|
||||
@@ -110,7 +129,14 @@ class AniXStreamApp(MDApp):
|
||||
config.write()
|
||||
case "theme_style":
|
||||
self.theme_cls.theme_style = value
|
||||
|
||||
def on_stop(self):
|
||||
if self.animdl_streaming_subprocess:
|
||||
self.animdl_streaming_subprocess.terminate()
|
||||
|
||||
|
||||
# custom methods
|
||||
# TODO: move theme to a personalized class
|
||||
def search_for_anime(self,search_field,**kwargs):
|
||||
if self.manager_screens.current != "search screen":
|
||||
self.manager_screens.current = "search screen"
|
||||
@@ -120,21 +146,75 @@ class AniXStreamApp(MDApp):
|
||||
self.manager_screens.current = "anime screen"
|
||||
self.anime_screen.controller.update_anime_view(id)
|
||||
|
||||
def stream_anime_with_animdl(self,title):
|
||||
self.animdl_streaming_subprocess = AnimdlApi.stream_anime_by_title(title)
|
||||
self.stop_streaming = False
|
||||
def watch_on_allanime(self,title_):
|
||||
"""
|
||||
Opens the given anime in your default browser on allanimes site
|
||||
Parameters:
|
||||
----------
|
||||
title_: The anime title requested to be opened
|
||||
"""
|
||||
if anime:=AnimdlApi.get_anime_url_by_title(title_):
|
||||
title,link = anime
|
||||
parsed_link = f"https://allmanga.to/bangumi/{link.split('/')[-1]}"
|
||||
else:
|
||||
show_notification("Failure",f"Failed to open {title} in browser on allanime site")
|
||||
if webbrowser.open(parsed_link):
|
||||
show_notification("Success",f"Successfully opened {title} in browser allanime site")
|
||||
else:
|
||||
show_notification("Failure",f"Failed to open {title} in browser on allanime site")
|
||||
|
||||
|
||||
|
||||
def open_download_anime_dialog(self):
|
||||
""""
|
||||
calls the download dialog
|
||||
"""
|
||||
DownloadAnimePopup().open()
|
||||
def download_anime(self,on_complete,on_progress,default_cmds:dict[str,str]|None=None,custom_cmds:tuple[str]|None=None):
|
||||
# TODO:Add custom download cmds functionality
|
||||
output_path = self.config.get("Preferences","downloads_dir")
|
||||
if default_cmds:
|
||||
if episodes_range:=default_cmds.get("episodes_range"):
|
||||
download_task =lambda: AnimdlApi.download_anime_by_title(default_cmds["title"],on_progress,on_complete,output_path,episodes_range,default_cmds["quality"])
|
||||
self.downloads_queue.put(download_task)
|
||||
else:
|
||||
download_task =lambda: AnimdlApi.download_anime_by_title(default_cmds["title"],on_progress,on_complete,output_path,None,default_cmds["quality"])
|
||||
self.downloads_queue.put(download_task)
|
||||
|
||||
def stream_anime_with_custom_input_cmds(self,*cmds):
|
||||
self.animdl_streaming_subprocess = AnimdlApi.run_custom_command("stream",*cmds)
|
||||
|
||||
def stream_anime_by_title_with_animdl(self,title,episodes_range:str|None=None):
|
||||
self.animdl_streaming_subprocess = AnimdlApi.stream_anime_by_title(title,episodes_range)
|
||||
# self.stop_streaming = False
|
||||
|
||||
def watch_on_animdl(self,title_dict:dict):
|
||||
def watch_on_animdl(self,title_dict:dict|None=None,episodes_range:str|None=None,custom_options:tuple[str]|None=None):
|
||||
"""
|
||||
Enables you to stream an anime using animdl either by parsing a title or custom animdl options
|
||||
|
||||
parameters:
|
||||
-----------
|
||||
title_dict:dict["japanese","kanji"]
|
||||
a dictionary containing the titles of the anime
|
||||
custom_options:tuple[str]
|
||||
a tuple containing valid animdl stream commands
|
||||
"""
|
||||
if self.animdl_streaming_subprocess:
|
||||
self.animdl_streaming_subprocess.terminate()
|
||||
if title:=title_dict.get("japanese"):
|
||||
stream_func = lambda: self.stream_anime_with_animdl(title)
|
||||
self.queue.put(stream_func)
|
||||
elif title:=title_dict.get("english"):
|
||||
stream_func = lambda:self.stream_anime_with_animdl(title)
|
||||
|
||||
if title_dict:
|
||||
if title:=title_dict.get("japanese"):
|
||||
stream_func = lambda: self.stream_anime_by_title_with_animdl(title,episodes_range)
|
||||
self.queue.put(stream_func)
|
||||
elif title:=title_dict.get("english"):
|
||||
stream_func = lambda:self.stream_anime_by_title_with_animdl(title,episodes_range)
|
||||
self.queue.put(stream_func)
|
||||
else:
|
||||
stream_func = lambda:self.stream_anime_with_custom_input_cmds(*custom_options)
|
||||
self.queue.put(stream_func)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# try:
|
||||
AniXStreamApp().run()
|
||||
# except:
|
||||
# print(plyer.storagepath.get_videos_dir())
|
||||
@@ -1 +1 @@
|
||||
{"my_list": {"list": [1535, 20605, 21519, 21, 5114, 133007, 166710, 116674, 11061, 21745, 9253, 153406, 166613, 133845, 143103, 20996, 162804]}}
|
||||
{"my_list": {"list": [1535, 20605, 21519, 21, 5114, 133007, 166710, 116674, 11061, 21745, 9253, 153406, 166613, 133845, 143103, 20996, 162804, 125367, 21827]}}
|
||||
Reference in New Issue
Block a user