Skip to content
26 changes: 26 additions & 0 deletions python/src/video.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def __init__(self, video_title: str, video_id: str, video_tags: Sequence[str]):
"""Video constructor."""
self._title = video_title
self._video_id = video_id
self._flag = None

# Turn the tags into a tuple here so it's unmodifiable,
# in case the caller changes the 'video_tags' they passed to us
Expand All @@ -29,3 +30,28 @@ def video_id(self) -> str:
def tags(self) -> Sequence[str]:
"""Returns the list of tags of a video."""
return self._tags

@property
def flag(self):
"""Returns a flag reason"""
return self._flag

def set_flag(self, flag_reason: str):
"""Flags video with a supplied reason"""
self._flag = flag_reason

def allow(self):
"""Remove flag from video"""
self._flag = None

def __str__(self):
return f"{self.title} ({self.video_id}) [{' '.join(self.tags)}]"

def __eq__(self, other):
return self.__str__() == other.__str__()

def __lt__(self, other):
return self.__str__() < other.__str__()

def __gt__(self, other):
return self.__str__() > other.__str__()
247 changes: 224 additions & 23 deletions python/src/video_player.py
Original file line number Diff line number Diff line change
@@ -1,63 +1,147 @@
"""A video player class."""

from .video_library import VideoLibrary
from .video import Video
from .video_playlist import Playlist

import enum


class Messages(enum.Enum):
NO_VIDEO_PLAYING = "No video is currently playing"
VIDEO_NOT_PAUSED = "Video is not paused"
VIDEO_NOT_EXISTS = "Video does not exist"
VIDEOS_NOT_AVAILABLE = "No videos available"
PLAYLIST_NAME_EXISTS = "A playlist with the same name already exists"
PLAYLIST_NOT_EXIST = "Playlist does not exist"
VIDEO_IN_PLAYLIST = "Video already added"
VIDEO_NOT_IN_PLAYLIST = "Video is not in playlist"
NO_VIDEOS_IN_PLAYLIST = "No videos here yet"
VIDEO_IS_FLAGGED = "Video is already flagged"
VIDEO_NOT_FLAGGED = "Video is not flagged"


class VideoStatus(enum.Enum):
PLAYING = "PLAYING"
PAUSED = "PAUSED"
STOPPED = "STOPPED"
FLAGGED = "FLAGGED"


class VideoPlayer:
"""A class used to represent a Video Player."""

def __init__(self):
self._video_library = VideoLibrary()
self.currently_playing = None
self.playing_status = None
self.playlists = {}

def number_of_videos(self):
num_videos = len(self._video_library.get_all_videos())
print(f"{num_videos} videos in the library")

def show_all_videos(self):
"""Returns all videos."""

print("show_all_videos needs implementation")
print("Here's a list of all available videos:")
library = self._video_library.get_all_videos()
library.sort()
for video in library:
if video.flag:
print(video, f"- {VideoStatus.FLAGGED.value} (reason: {video.flag})")
else:
print(video)

def play_video(self, video_id):
"""Plays the respective video.

Args:
video_id: The video_id to be played.
"""
print("play_video needs implementation")
video = self._video_library.get_video(video_id)
if not video:
print("Cannot play video:", Messages.VIDEO_NOT_EXISTS.value)
else:
self.play_known_video(video)

def play_known_video(self, video: Video):
"""Plays a known video that exists in the Video Library

Args:
video: An already known video that exists in the video library
"""
if self.playing_status in [VideoStatus.PLAYING, VideoStatus.PAUSED]:
self.stop_video()

if video.flag:
print(f"Cannot play video: Video is currently flagged (reason: {video.flag})")
else:
print("Playing video:", video.title)
self.currently_playing = video
self.playing_status = VideoStatus.PLAYING

def stop_video(self):
"""Stops the current video."""

print("stop_video needs implementation")
if self.playing_status == VideoStatus.STOPPED or not self.currently_playing:
print("Cannot stop video:", Messages.NO_VIDEO_PLAYING.value)
else:
print("Stopping video:", self.currently_playing.title)
self.playing_status = VideoStatus.STOPPED

def play_random_video(self):
"""Plays a random video from the video library."""
import random

print("play_random_video needs implementation")
unflagged_library = [video for video in self._video_library.get_all_videos() if not video.flag]
try:
video = random.choice(unflagged_library)
self.play_known_video(video)
except IndexError:
print(Messages.VIDEOS_NOT_AVAILABLE.value)

def pause_video(self):
"""Pauses the current video."""

print("pause_video needs implementation")
if self.playing_status == VideoStatus.PLAYING:
print("Pausing video:", self.currently_playing.title)
self.playing_status = VideoStatus.PAUSED
elif self.playing_status == VideoStatus.PAUSED:
print("Video already paused:", self.currently_playing.title)
else:
print("Cannot pause video:", Messages.NO_VIDEO_PLAYING.value)

def continue_video(self):
"""Resumes playing the current video."""

print("continue_video needs implementation")
if self.playing_status == VideoStatus.PAUSED:
print("Continuing video:", self.currently_playing.title)
self.playing_status = VideoStatus.PLAYING
elif self.playing_status == VideoStatus.STOPPED or not self.currently_playing:
print("Cannot continue video:", Messages.NO_VIDEO_PLAYING.value)
else:
print("Cannot continue video:", Messages.VIDEO_NOT_PAUSED.value)

def show_playing(self):
"""Displays video currently playing."""
if self.playing_status == VideoStatus.STOPPED or not self.currently_playing:
print(Messages.NO_VIDEO_PLAYING.value)

print("show_playing needs implementation")
if self.playing_status == VideoStatus.PLAYING:
print("Currently playing:", self.currently_playing)

if self.playing_status == VideoStatus.PAUSED:
print("Currently playing:", self.currently_playing, "-", VideoStatus.PAUSED.value)

def create_playlist(self, playlist_name):
"""Creates a playlist with a given name.

Args:
playlist_name: The playlist name.
"""
print("create_playlist needs implementation")
name = playlist_name.lower()
if not name in self.playlists:
self.playlists[name] = Playlist(playlist_name)
print("Successfully created new playlist:", self.playlists[name])
else:
print("Cannot create playlist:", Messages.PLAYLIST_NAME_EXISTS.value)

def add_to_playlist(self, playlist_name, video_id):
"""Adds a video to a playlist with a given name.
Expand All @@ -66,20 +150,53 @@ def add_to_playlist(self, playlist_name, video_id):
playlist_name: The playlist name.
video_id: The video_id to be added.
"""
print("add_to_playlist needs implementation")
video = self._video_library.get_video(video_id)
name = playlist_name.lower()
if name in self.playlists and video:
if video.flag:
print(f"Cannot add video to {playlist_name}: Video is currently flagged (reason: {video.flag})")
elif self.playlists[name].add_video(video):
print(f"Added video to {playlist_name}:", video.title)
else:
print(f"Cannot add video to {playlist_name}:", Messages.VIDEO_IN_PLAYLIST.value )
elif name not in self.playlists:
print(f"Cannot add video to {playlist_name}:", Messages.PLAYLIST_NOT_EXIST.value)
elif not video:
print(f"Cannot add video to {playlist_name}:", Messages.VIDEO_NOT_EXISTS.value)
else:
pass

def show_all_playlists(self):
"""Display all playlists."""

print("show_all_playlists needs implementation")
if self.playlists:
playlist_names = list(self.playlists)
playlist_names.sort()
print("Showing all playlists:")
for name in playlist_names:
print(self.playlists[name])
else:
print("No playlists exist yet")

def show_playlist(self, playlist_name):
"""Display all videos in a playlist with a given name.

Args:
playlist_name: The playlist name.
"""
print("show_playlist needs implementation")
name = playlist_name.lower()
if name in self.playlists:
playlist = self.playlists[name]
print("Showing playlist:", playlist_name, f"({len(playlist.videos)}) video{''.join(['s' for _ in range(1) if len(playlist.videos) > 1])}")
if len(playlist.videos) > 0:
for video in playlist.videos:
if video.flag:
print(video, f"- {VideoStatus.FLAGGED.value} (reason: {video.flag})")
else:
print(video)
else:
print(Messages.NO_VIDEOS_IN_PLAYLIST.value)
else:
print(f"Cannot show playlist {playlist_name}:", Messages.PLAYLIST_NOT_EXIST.value)

def remove_from_playlist(self, playlist_name, video_id):
"""Removes a video to a playlist with a given name.
Expand All @@ -88,39 +205,102 @@ def remove_from_playlist(self, playlist_name, video_id):
playlist_name: The playlist name.
video_id: The video_id to be removed.
"""
print("remove_from_playlist needs implementation")
name = playlist_name.lower()
video = self._video_library.get_video(video_id)
if name in self.playlists:
playlist = self.playlists[name]
if video:
if self.playlists[name].remove_video(video):
print(f"Removed video from {playlist_name}:", video)
else:
print(f"Cannot remove video from {playlist}:", Messages.VIDEO_NOT_IN_PLAYLIST.value )
else:
print(f"Cannot remove video from {playlist_name}:", Messages.VIDEO_NOT_EXISTS.value)
else:
print(f"Cannot remove video from {playlist_name}:", Messages.PLAYLIST_NOT_EXIST.value)

def clear_playlist(self, playlist_name):
"""Removes all videos from a playlist with a given name.

Args:
playlist_name: The playlist name.
"""
print("clears_playlist needs implementation")
name = playlist_name.lower()
if name in self.playlists:
playlist = self.playlists[name]
if len(playlist.videos) == 0:
print(Messages.NO_VIDEOS_IN_PLAYLIST.value)
else:
playlist.clear_videos()
print(f"Successfully removed all videos from {playlist_name}")
else:
print(f"Cannot clear playlist {playlist_name}:", Messages.PLAYLIST_NOT_EXIST.value)

def delete_playlist(self, playlist_name):
"""Deletes a playlist with a given name.

Args:
playlist_name: The playlist name.
"""
print("deletes_playlist needs implementation")
name = playlist_name.lower()
if name in self.playlists:
self.playlists.pop(name)
print("Deleted playlist:", name)
else:
print(f"Cannot delete playlist {playlist_name}:", Messages.PLAYLIST_NOT_EXIST.value)

def play_selected_video(self, results: list[Video]):
print("Would you like to play any of the above? If yes, specify the number of the video.")
print("If your answer is not a valid number, we will assume it's a no.")

user_choice = input().strip()
if user_choice.isdecimal() and int(user_choice) <= len(results):
user_choice = int(user_choice)
self.play_known_video(results[user_choice - 1])
else:
pass

def search_videos(self, search_term):
"""Display all the videos whose titles contain the search_term.

Args:
search_term: The query to be used in search.
"""
print("search_videos needs implementation")
results = []
unflagged_library = [video for video in self._video_library.get_all_videos() if not video.flag]
for video in unflagged_library:
if search_term.lower() in video.title.lower():
results.append(video)

if len(results) == 0:
print(f"No search results for {search_term}")
else:
results.sort()
print(f"Here are the results for {search_term}:")
for (index, hit) in enumerate(results):
print(f"{index + 1}) {hit}")
self.play_selected_video(results)

def search_videos_tag(self, video_tag):
"""Display all videos whose tags contains the provided tag.

Args:
video_tag: The video tag to be used in search.
"""
print("search_videos_tag needs implementation")
results = []
unflagged_library = [video for video in self._video_library.get_all_videos() if not video.flag]
for video in unflagged_library:
video_tags = [tag.lower() for tag in video.tags]
if video_tag.lower() in video_tags:
results.append(video)
if len(results) == 0:
print(f"No search results for {video_tag}:")
else:
results.sort()
print(f"Here are the results for {video_tag}:")
for (index, hit) in enumerate(results):
print(f"{index + 1}) {hit}")
self.play_selected_video(results)

def flag_video(self, video_id, flag_reason=""):
"""Mark a video as flagged.
Expand All @@ -129,12 +309,33 @@ def flag_video(self, video_id, flag_reason=""):
video_id: The video_id to be flagged.
flag_reason: Reason for flagging the video.
"""
print("flag_video needs implementation")
video = self._video_library.get_video(video_id)
if video:
if not video.flag:
if flag_reason =="":
flag_reason = "Not supplied"
if self.playing_status in [VideoStatus.PLAYING, VideoStatus.PAUSED] and video == self.currently_playing:
self.stop_video()
video.set_flag(flag_reason)
print("Successfully flagged video:", video.title, f"(reason: {video.flag})")
else:
print("Cannot flag video:", Messages.VIDEO_IS_FLAGGED.value)
else:
print("Cannot flag video:", Messages.VIDEO_NOT_EXISTS.value)

def allow_video(self, video_id):
"""Removes a flag from a video.

Args:
video_id: The video_id to be allowed again.
"""
print("allow_video needs implementation")
video = self._video_library.get_video(video_id)

if video :
if video.flag:
video.allow()
print("Successfully removed flag from video:", video.title)
elif not video.flag:
print("Cannot remove flag from video:", Messages.VIDEO_NOT_FLAGGED.value)
else:
print("Cannot remove flag from video:", Messages.VIDEO_NOT_EXISTS.value)
Loading