edited anime episode to stream response (better experience)

This commit is contained in:
Francesco Grazioso 2024-05-04 00:04:19 +02:00
parent 594db0272a
commit 6b22a90688
4 changed files with 92 additions and 27 deletions

View File

@ -2,6 +2,7 @@ import json
import os import os
from django.core.paginator import Paginator from django.core.paginator import Paginator
from django.http import StreamingHttpResponse
from rest_framework import viewsets from rest_framework import viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
@ -50,7 +51,6 @@ class SearchView(viewsets.ViewSet):
self.media_id = request.query_params.get("media_id") self.media_id = request.query_params.get("media_id")
self.media_slug = request.data.get("media_slug") self.media_slug = request.data.get("media_slug")
self.type_media = request.query_params.get("type_media") self.type_media = request.query_params.get("type_media")
self.page = self.request.query_params.get("page")
try: try:
match self.type_media: match self.type_media:
@ -81,22 +81,18 @@ class SearchView(viewsets.ViewSet):
return Response({"episodes": episodes}) return Response({"episodes": episodes})
case "TV_ANIME": case "TV_ANIME":
episodes = [] def stream_episodes():
episodes_downloader = EpisodeDownloader( episodes_downloader = EpisodeDownloader(self.media_id, self.media_slug)
self.media_id, self.media_slug episoded_count = episodes_downloader.get_count_episodes()
)
episoded_count = episodes_downloader.get_count_episodes()
items_per_page = 5
paginator = Paginator(range(episoded_count), items_per_page)
page_number = self.page if self.page else 1 for i in range(1, episoded_count+1):
page_indices = paginator.page(page_number) episode_info = episodes_downloader.get_info_episode(index_ep=i)
episode_info["episode_id"] = i
print(f"Getting episode {i} of {episoded_count} info...")
yield f'data: {json.dumps(episode_info)}\n\n'
for i in page_indices: response = StreamingHttpResponse(stream_episodes(), content_type='text/event-stream')
episode_info = episodes_downloader.get_info_episode(index_ep=i) return response
episode_info["episode_id"] = i
episodes.append(episode_info)
return Response({"episodes": episodes})
except Exception as e: except Exception as e:
return Response( return Response(
{ {

View File

@ -1,5 +1,5 @@
import axios from 'axios'; import axios from 'axios'
import type {MediaItemResponse} from "@/api/interfaces"; import type {MediaItemResponse} from '@/api/interfaces'
const BASE_URL = 'http://127.0.0.1:8000/api' const BASE_URL = 'http://127.0.0.1:8000/api'
@ -13,4 +13,19 @@ function get(url: string): Promise<any> {
export default function search(query: string, type: string) : Promise<MediaItemResponse> { export default function search(query: string, type: string) : Promise<MediaItemResponse> {
return get(`/search?search_terms=${query}&type=${type}`) return get(`/search?search_terms=${query}&type=${type}`)
}
export async function getEpisodesInfo(mediaId: number, mediaSlug: string, mediaType: string): Promise<Response> {
const url = `${BASE_URL}/search/get_episodes_info?media_id=${mediaId}&media_slug=${mediaSlug}&type_media=${mediaType}`;
if (mediaType === 'TV_ANIME') {
return await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'text/event-stream'
}
});
} else {
return Promise.resolve(new Response());
}
} }

View File

@ -22,4 +22,24 @@ export interface MediaItem {
export interface MediaItemResponse { export interface MediaItemResponse {
media: MediaItem[]; media: MediaItem[];
}
export interface EpisodeAnime {
id: number;
anime_id: number;
user_id: number | null;
number: string;
created_at: string;
link: string;
visite: number;
hidden: number;
public: number;
scws_id: number;
file_name: string;
tg_post: number;
episode_id: number;
}
export interface EpisodeAnimeResponse {
episodes: EpisodeAnime[];
} }

View File

@ -1,3 +1,38 @@
<script setup lang="ts">
import { useRoute } from 'vue-router'
import type { EpisodeAnime, MediaItem } from "@/api/interfaces";
import { onMounted, ref, onUnmounted } from "vue";
import { getEpisodesInfo } from "@/api/api";
const route = useRoute()
const item: MediaItem = JSON.parse(<string>route.params.item)
const imageUrl: string = <string>route.params.imageUrl
const episodes = ref<EpisodeAnime[]>([])
const loading = ref(false)
onMounted(async () => {
if (item.type !== 'TV_ANIME' && item.type !== 'TV') {
return
}
loading.value = true
const response = await getEpisodesInfo(item.id, item.slug, item.type)
if (response && response.body) {
loading.value = false;
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
const episodesData:EpisodeAnime = JSON.parse(value.split("a:")[1].trim());
episodes.value.push(episodesData);
}
}
})
</script>
<template> <template>
<div class="details-container"> <div class="details-container">
<div class="details-card"> <div class="details-card">
@ -11,22 +46,21 @@
</div> </div>
</div> </div>
</div> </div>
<div class="episodes-container">
<div v-if="!loading" v-for="episode in episodes" :key="episode.id" class="episode-item">
<div class="episode-title">{{ episode.number }} - {{ episode.file_name }}</div>
</div>
<div v-else>
<p>Loading...</p>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts">
import { useRoute } from 'vue-router'
import type { MediaItem } from "@/api/interfaces";
const route = useRoute()
const item: MediaItem = JSON.parse(<string>route.params.item)
const imageUrl: string = <string>route.params.imageUrl
</script>
<style scoped> <style scoped>
.details-container { .details-container {
padding-top: 10px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
min-height: 100vh; min-height: 100vh;