diff --git a/test.py b/test.py index fad0dab..cd64863 100644 --- a/test.py +++ b/test.py @@ -8,16 +8,19 @@ import wave from datetime import datetime, timedelta from enum import Enum, auto from typing import Callable, TypedDict +from io import BytesIO import cv2 import emoji import ephem +import numpy as np import pygame import pygame.gfxdraw import pytchat import requests from cv2 import VideoCapture from ephem import Moon, Observer, Sun +from pydub import AudioSegment from pygame import Rect, Surface from pygame.font import Font from pygame.mixer import Sound @@ -50,6 +53,7 @@ def main ( x = CWindow.WIDTH * 3 / 4, y = CWindow.HEIGHT - 120, balloon = balloon) + Video (game, 'snack_time.mp4').play () CurrentTime (game, SYSTEM_FONT) try: broadcast = Broadcast (os.environ['BROADCAST_CODE']) @@ -639,16 +643,6 @@ class Jojoko (GameObject): def redraw ( self, - ) -> None: - if self.frame % (FPS * 3600) == 0: - self.surface = self._get_surface () - surface = pygame.transform.rotate (self.surface, -(90 + math.degrees (self.arg))) - surface.set_colorkey ((0, 255, 0)) - self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y))) - super ().redraw () - - def update ( - self, ) -> None: self.moon.compute (self.game.sky.observer) self.alt = self.moon.alt @@ -657,7 +651,12 @@ class Jojoko (GameObject): self.arg = self.new_arg self.x = self.new_x self.y = self.new_y - super ().update () + if self.frame % (FPS * 3600) == 0: + self.surface = self._get_surface () + surface = pygame.transform.rotate (self.surface, -(90 + math.degrees (self.arg))) + surface.set_colorkey ((0, 255, 0)) + self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y))) + super ().redraw () @property def phase ( @@ -732,30 +731,6 @@ class CWindow: HEIGHT = 768 -def get_surfaces_from_video ( - video_path: str, -) -> list[Surface]: - cap = VideoCapture (video_path) - if not cap.isOpened (): - return [] - - fps = cap.get (cv2.CAP_PROP_FPS) - - surfaces: list[Surface] = [] - while cap.isOpened (): - (ret, frame) = cap.read () - if not ret: - break - frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB) - frame_surface = pygame.surfarray.make_surface (frame) - frame_surface = pygame.transform.rotate (frame_surface, -90) - surfaces.append (pygame.transform.flip (frame_surface, True, False)) - - cap.release () - - return surfaces - - class Broadcast: chat: PytchatCore @@ -777,6 +752,126 @@ class Broadcast: return random.choice (chats) +class NicoVideo (Video): + ... + + +class Video (GameObject): + fps: int + pausing: bool = False + sound: Sound + surfaces: list[Surface] + + def __init__ ( + self, + game: Game, + path: str, + ): + super ().__init__ (game) + self.pausing = False + (self.surfaces, self.fps) = self._create_surfaces (path) + self.sound = self._create_sound (path) + self.stop () + + def _create_sound ( + self, + path: str, + ) -> Sound: + bytes_io = BytesIO () + audio = AudioSegment.from_file (path, format = path.split ('.')[-1]) + audio.export (bytes_io, format = 'wav') + bytes_io.seek (0) + return pygame.mixer.Sound (bytes_io) + + def _create_surfaces ( + self, + path: str, + ) -> tuple[list[Surface], int]: + cap = self._load (path) + surfaces: list[Surface] = [] + if cap is None: + return ([], FPS) + fps = int (cap.get (cv2.CAP_PROP_FPS)) + while cap.isOpened (): + frame = self._read_frame (cap) + if frame is None: + break + surfaces.append (self._convert_to_surface (frame)) + new_surfaces: list[Surface] = [] + for i in range (len (surfaces) * FPS // fps): + new_surfaces.append (surfaces[i * fps // FPS]) + return (new_surfaces, fps) + + def _load ( + self, + path: str, + ) -> VideoCapture | None: + """ + OpenCV で動画を読込む. + """ + cap = VideoCapture (path) + if cap.isOpened (): + return cap + return None + + def _read_frame ( + self, + cap: VideoCapture, + ) -> np.ndarray | None: + """ + 動画のフレームを読込む. + """ + ret: bool + frame: np.ndarray + (ret, frame) = cap.read () + if ret: + return frame + return None + + def _convert_to_surface ( + self, + frame: np.ndarray, + ) -> Surface: + frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB) + frame_surface = pygame.surfarray.make_surface (frame) + frame_surface = pygame.transform.rotate (frame_surface, -90) + frame_surface = pygame.transform.flip (frame_surface, True, False) + return frame_surface + + def play ( + self, + ) -> None: + self.enabled = True + self.pausing = False + self.sound.play () + + def stop ( + self, + ) -> None: + self.enabled = False + self.frame = 0 + + def pause ( + self, + ) -> None: + self.pausing = True + + def redraw ( + self, + ) -> None: + self.game.screen.blit (self.surfaces[self.frame], (self.x, self.y)) + super ().redraw () + + def update ( + self, + ) -> None: + if self.frame >= len (self.surfaces) - 1: + self.pause () + if self.pausing: + self.frame -= 1 + super ().update () + + def fetch_bytes_from_url ( url: str, ) -> bytes | None: