AI 移行 #38
@@ -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:
|
||||
|
||||
新しい課題から参照
ユーザをブロックする