Feat/app api and frontend (#140)

* minor fixes

* created basic django app

* add django dependency

* created basic search endpoint

* created retrieve method for search

* remove retrieve

* start implementing download endpoint (only movie for now)

* start implementing episode info for series

* finished get_episodes_info

* minor fixes

* add download anime episode

* start implementing download for tv series

* refactor methods

* finished download endpoint (will implement possibility to download single episodes of season in tv series)

* new domain and black on project

* start

* add cors

* add start gui command

* add gui for search

* edited .gitignore

* create component for media details

* better UX/UI

* edited anime episode to stream response (better experience)

* implemented UI for media details (TODO add download capabilities)

* fix poster fetching

* minor fixes

* fix cors error

* start implementing download

* fix typing on anime movies

* refactor

* refactor + add download OVA

* add plot for all anime types

* add download for all anime episodes

* add download all tv series episodes

* fix crach if localStorage is undefined

* moved download logic in separeted file

* fix wrong index passed while downloading tv series

* fix style searchbar

* add loader to search button and add enter listener while searching

* remove dependency from loading episodes to download all in anime series

* add function to download selected episodes for anime

* add sh command to kill gui

* fix messages in kill_gui.sh

* start implementing download select episodes for tv series (to be tested) + run black and eslint

* start  refactoring  to version 2.0

* start implementing preview endpoint

* finish reimplement version 2.0
This commit is contained in:
Francesco Grazioso 2024-06-01 13:13:09 +02:00 committed by GitHub
parent 306377a7be
commit 1c5f960b16
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 66 additions and 73 deletions

View File

@ -26,37 +26,40 @@ video_source = VideoSource()
def download_episode(index_select: int):
def download_episode(index_select: int, custom_video_source: VideoSource = None):
"""
Downloads the selected episode.
Args:
- index_select (int): Index of the episode to download.
"""
active_video_source = custom_video_source if custom_video_source is not None else video_source
# Get information about the selected episode
obj_episode = video_source.get_info_episode(index_select)
obj_episode = active_video_source.get_info_episode(index_select)
start_message()
console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n")
# Get the embed URL for the episode
embed_url = video_source.get_embed(obj_episode.id)
embed_url = active_video_source.get_embed(obj_episode.id)
# Parse parameter in embed text
video_source.parse_script(embed_url)
active_video_source.parse_script(embed_url)
# Create output path
mp4_path = None
mp4_name = f"{index_select + 1}.mp4"
if video_source.is_series:
mp4_path = os.path.join(ROOT_PATH, ANIME_FOLDER, SERIES_FOLDER, video_source.series_name)
if active_video_source.is_series:
mp4_path = os.path.join(ROOT_PATH, ANIME_FOLDER, SERIES_FOLDER, active_video_source.series_name)
else:
mp4_path = os.path.join(ROOT_PATH, ANIME_FOLDER, MOVIE_FOLDER, video_source.series_name)
mp4_path = os.path.join(ROOT_PATH, ANIME_FOLDER, MOVIE_FOLDER, active_video_source.series_name)
# Crete downloader
obj_download = Downloader(
m3u8_playlist = video_source.get_playlist(),
m3u8_playlist = active_video_source.get_playlist(),
output_filename = os.path.join(mp4_path, mp4_name)
)

View File

@ -66,7 +66,7 @@ def display_episodes_list() -> str:
return last_command
def donwload_video(tv_name: str, index_season_selected: int, index_episode_selected: int) -> None:
def donwload_video(tv_name: str, index_season_selected: int, index_episode_selected: int, custom_video_source: VideoSource = None) -> None:
"""
Download a single episode video.
@ -76,10 +76,12 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec
- index_episode_selected (int): Index of the selected episode.
"""
active_video_source = custom_video_source if custom_video_source is not None else video_source
start_message()
# Get info about episode
obj_episode = video_source.obj_episode_manager.episodes[index_episode_selected - 1]
obj_episode = active_video_source.obj_episode_manager.episodes[index_episode_selected - 1]
console.print(f"[yellow]Download: [red]{index_season_selected}:{index_episode_selected} {obj_episode.name}")
print()
@ -88,9 +90,9 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec
mp4_path = os.path.join(ROOT_PATH, STREAMING_FOLDER, SERIES_FOLDER, tv_name, f"S{index_season_selected}")
# Retrieve scws and if available master playlist
video_source.get_iframe(obj_episode.id)
video_source.get_content()
master_playlist = video_source.get_playlist()
active_video_source.get_iframe(obj_episode.id)
active_video_source.get_content()
master_playlist = active_video_source.get_playlist()
# Download the episode
Downloader(
@ -99,7 +101,7 @@ def donwload_video(tv_name: str, index_season_selected: int, index_episode_selec
).start(SERVER_IP)
def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: bool = False) -> None:
def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: bool = False, custom_video_source: VideoSource = None) -> None:
"""
Download all episodes of a season.
@ -109,19 +111,21 @@ def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: boo
- donwload_all (bool): Donwload all seasons episodes
"""
active_video_source = custom_video_source if custom_video_source is not None else video_source
# Clean memory of all episodes and get the number of the season (some dont follow rule of [1,2,3,4,5] but [1,2,3,145,5,6,7]).
video_source.obj_episode_manager.clear()
season_number = (video_source.obj_title_manager.titles[index_season_selected-1].number)
active_video_source.obj_episode_manager.clear()
season_number = (active_video_source.obj_title_manager.titles[index_season_selected-1].number)
# Start message and collect information about episodes
start_message()
video_source.collect_title_season(season_number)
episodes_count = video_source.obj_episode_manager.get_length()
active_video_source.collect_title_season(season_number)
episodes_count = active_video_source.obj_episode_manager.get_length()
# Download all episodes wihtout ask
if donwload_all:
for i_episode in range(1, episodes_count+1):
donwload_video(tv_name, index_season_selected, i_episode)
donwload_video(tv_name, index_season_selected, i_episode, active_video_source)
console.print(f"\n[red]Download [yellow]season: [red]{index_season_selected}.")
@ -134,12 +138,12 @@ def donwload_episode(tv_name: str, index_season_selected: int, donwload_all: boo
# Download selected episodes
if len(list_episode_select) == 1 and last_command != "*":
donwload_video(tv_name, index_season_selected, list_episode_select[0])
donwload_video(tv_name, index_season_selected, list_episode_select[0],active_video_source)
# Download all other episodes selecter
else:
for i_episode in list_episode_select:
donwload_video(tv_name, index_season_selected, i_episode)
donwload_video(tv_name, index_season_selected, i_episode, active_video_source)
def download_series(tv_id: str, tv_name: str, version: str, domain: str) -> None:

View File

@ -319,7 +319,11 @@ class M3U8_Segments:
self.condition.notify_all() # Wake up the writer thread if it's waiting
# Register the signal handler for Ctrl+C
signal.signal(signal.SIGINT, signal_handler)
try:
signal.signal(signal.SIGINT, signal_handler)
except Exception as e:
logging.error(f"Failed to register signal handler: {e}")
logging.error("Ctrl+C detection may not work.")
with ThreadPoolExecutor(max_workers=TQDM_MAX_WORKER) as executor:

View File

@ -1,10 +1,10 @@
from rest_framework import routers
from .views import SearchView#, DownloadView
from .views import SearchView, DownloadView
router = routers.DefaultRouter()
router.register(r"search", SearchView, basename="search")
#router.register(r"download", DownloadView, basename="download")
router.register(r"download", DownloadView, basename="download")
urlpatterns = router.urls

View File

@ -7,10 +7,16 @@ from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from Src.Api.Animeunity.anime import donwload_film
from Src.Api.Animeunity.anime import download_episode as donwload_anime_episode
from Src.Api.Animeunity import title_search as anime_search
from Src.Api.Animeunity.Core.Vix_player.player import VideoSource as anime_source
from Src.Api.Animeunity.site import media_search_manager as anime_media_manager
from Src.Api.Streamingcommunity.film import download_film
from Src.Api.Streamingcommunity.series import donwload_episode as download_tv_episode
from Src.Api.Streamingcommunity import title_search as sc_search, get_version_and_domain
from Src.Api.Streamingcommunity.Core.Vix_player.player import VideoSource as film_video_source
from Src.Api.Streamingcommunity.site import media_search_manager as film_media_manager
@ -151,7 +157,7 @@ class SearchView(viewsets.ViewSet):
return Response({"error": "No media found with that search query"})
'''
class DownloadView(viewsets.ViewSet):
def create(self, request):
@ -171,59 +177,36 @@ class DownloadView(viewsets.ViewSet):
case "MOVIE":
download_film(self.media_id, self.media_slug, self.domain)
case "TV":
video_source = VideoSource()
video_source.set_url_base_name(STREAM_SITE_NAME)
video_source.set_version(self.site_version)
video_source.set_domain(self.domain)
video_source.set_series_name(self.media_slug)
video_source.set_media_id(self.media_id)
video_source = film_video_source()
video_source.setup(
version = self.site_version,
domain = self.domain,
media_id = self.media_id,
series_name = self.media_slug
)
video_source.collect_info_seasons()
video_source.obj_episode_manager.clear()
video_source.collect_title_season(self.download_id)
episodes_count = video_source.obj_episode_manager.get_length()
for i_episode in range(1, episodes_count + 1):
episode_id = video_source.obj_episode_manager.episodes[
i_episode - 1
].id
seasons_count = video_source.obj_title_manager.get_length()
# Define filename and path for the downloaded video
mp4_name = remove_special_characters(
f"{map_episode_title(self.media_slug,video_source.obj_episode_manager.episodes[i_episode - 1],self.download_id)}.mp4"
)
mp4_path = remove_special_characters(
os.path.join(
ROOT_PATH,
SERIES_FOLDER,
self.media_slug,
f"S{self.download_id}",
)
)
os.makedirs(mp4_path, exist_ok=True)
# Get iframe and content for the episode
video_source.get_iframe(episode_id)
video_source.get_content()
video_source.set_url_base_name(STREAM_SITE_NAME)
# Download the episode
obj_download = Downloader(
m3u8_playlist=video_source.get_playlist(),
key=video_source.get_key(),
output_filename=os.path.join(mp4_path, mp4_name),
)
obj_download.download_m3u8()
for i_season in range(1, seasons_count + 1):
download_tv_episode(self.media_slug, i_season, True, video_source)
case "TV_ANIME":
episodes_downloader = EpisodeDownloader(
self.media_id, self.media_slug
video_source = anime_source()
video_source.setup(
media_id = self.media_id,
series_name = self.media_slug
)
episodes_downloader.download_episode(self.download_id)
episoded_count = video_source.get_count_episodes()
for i in range(episoded_count):
donwload_anime_episode(i, video_source)
case "OVA" | "SPECIAL":
anime_download_film(
id_film=self.media_id, title_name=self.media_slug
donwload_film(
id_film=self.media_id,
title_name=self.media_slug
)
case _:
raise Exception("Type media not supported")
@ -238,4 +221,3 @@ class DownloadView(viewsets.ViewSet):
}
return Response(response_dict)
'''

View File

@ -148,7 +148,7 @@ const downloadAllItems = async () => {
@click.prevent="downloadAllItems">
Scarica {{['TV_ANIME', 'TV'].includes(item.type)? 'tutto' : ''}}
</button>
<template v-if="!loading && ['TV_ANIME', 'TV'].includes(item.type)">
<!--<template v-if="!loading && ['TV_ANIME', 'TV'].includes(item.type)">
<button @click="toggleEpisodeSelection">
{{selectingEpisodes ? 'Disattiva' : 'Attiva'}} selezione episodi
</button>
@ -156,7 +156,7 @@ const downloadAllItems = async () => {
@click="downloadSelectedEpisodes">
Download episodi selezionati
</button>
</template>
</template>-->
</div>
</div>
</div>
@ -194,7 +194,7 @@ const downloadAllItems = async () => {
<!--MOVIES SECTION-->
<div v-else-if="!loading && ['MOVIE', 'OVA', 'SPECIAL'].includes(item.type)">
<p>Questo è un {{item.type}} (QUESTO TESTO E' A SCOPO DI TEST)</p>
<!-- WILL BE POPULATED WITH HYPOTETICAL MOVIES CONTENT -->
</div>
<!--LOADING SECTION-->