Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Youtube Search Plugin #1152

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
267 changes: 267 additions & 0 deletions jarviscli/plugins/youtube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
import argparse
import os
import time
import webbrowser

import requests
import rich
import youtube_search
import youtubesearchpython
from plugin import plugin, require


@require(network=True)
@plugin("youtube")
def youtube(jarvis, s):
from rich import print
from rich.console import Console
from rich.markdown import Markdown
from rich.panel import Panel
from rich.progress import Progress
from rich.prompt import Confirm, Prompt
from rich.table import Table
from rich.text import Text
from youtube_search import YoutubeSearch
from youtubesearchpython import (
ChannelSearch,
ChannelsSearch,
CustomSearch,
Search,
Video,
VideoSortOrder,
)

console = Console()
parser = argparse.ArgumentParser(prog="Youtube Terminal Play and Search")
parser.add_argument("search_term", help="Youtube Search Query")
parser.add_argument(
"-v", "--version", action="version", version="%(prog)s 1.1 : The Search Update"
)
parser.add_argument("-o", help="Open Latest Video in mpv", action="store_true")
parser.add_argument("-c", help="Channel Info", action="store_true")
parser.add_argument(
"-p", help="Play the Video Link or First Relevant Video", action="store_true"
)
parser.add_argument("--info", help="Video Info", action="store_true")
parser.add_argument(
"-l",
help="More Relevant Results and more formatting, but slower",
action="store_true",
)
args = parser.parse_args(jarvis.input().split())

def shortener(url):
web_to_visit = f"https://tinyurl.com/api-create.php?url={url}"
website = requests.get(web_to_visit)
final_url_raw = str(website.content)
final_url_semi_raw = final_url_raw.replace("b'", "")
final_url = final_url_semi_raw.replace("'", "")
return final_url

def search_yt(search_term):
if args.o:
customSearch = CustomSearch(search_term, VideoSortOrder.uploadDate, limit=1)
latest_video = customSearch.result()
console.print(
f':new: Latest Video from {latest_video["result"][0]["channel"]["name"]}'
)
console.print(
f'{latest_video["result"][0]["title"]} released {latest_video["result"][0]["publishedTime"]}.'
)
play_video = Confirm.ask("Do you want to play in mpv")
if play_video:
with Progress() as progress:
task1 = progress.add_task("[green]Loading Player...", total=1000)
while not progress.finished:
time.sleep(0.01)
progress.update(task1, advance=5)
try:
os.system(
f'mpv --fullscreen --no-terminal --title="youtube - Playing {latest_video["result"][0]["title"]} from {latest_video["result"][0]["channel"]["name"]}" {latest_video["result"][0]["link"]}'
)
except:
webbrowser.open(
f'https://www.youtube-nocookie.com/embed/{custom_play_search_content["result"][0]["id"]}'
)
quit()
if args.l:
table = Table(
title=Panel(f"Results for [red]{search_term.capitalize()}"),
show_header=True,
header_style="bold green",
)
table.add_column("Released", style="dim", width=20)
table.add_column("Title", style="yellow")
table.add_column("Channel", style="cyan")
table.add_column("Url", no_wrap=True, style="dim blue")

results = YoutubeSearch(search_term, max_results=20).to_dict()
for i in results:
video_url_for_table = f'https://youtu.be/{i["id"]}'
channel = i["channel"]
channelsSearch = ChannelsSearch(channel, limit=10, region="US")
channelsSearch_content = channelsSearch.result()
table.add_row(
i["publish_time"],
i["title"],
f'[link={channelsSearch_content["result"][0]["link"]}]{channel}[/link]',
video_url_for_table,
)
console.print(table)
quit()
if args.c:
channel_to_search = args.search_term
channelsSearch = ChannelsSearch(channel_to_search, limit=10, region="US")
channelsSearch_content = channelsSearch.result()
console.print(
Panel(f"Details for [red]{channel_to_search.capitalize()}"),
justify="center",
)
console.print(
Panel(
f'[green bold]Channel Name: [/] {channelsSearch_content["result"][0]["title"]}\n[green bold]Subscribers: [/] {channelsSearch_content["result"][0]["subscribers"]}\n[green bold]Link: [/] [cyan dim]{shortener(channelsSearch_content["result"][0]["link"])}[/]\n[green bold]Description: [/]{channelsSearch_content["result"][0]["descriptionSnippet"][0]["text"]}\n[green bold]Video Count: [/]{channelsSearch_content["result"][0]["videoCount"]}'
),
justify="center",
)
if args.p:
custom_play_search_term = args.search_term
if "https://youtu" in custom_play_search_term:
video_url = args.search_term
video_info = Video.getInfo(video_url)
console.print(
Panel(
f'[cyan]{video_info["title"]}[/]\n\n[green bold]Url: [/]{video_info["link"]}\n[green bold]View Count: [/]{video_info["viewCount"]["text"]}\n[green bold]Channel: [/]{video_info["channel"]["name"]}\n[green bold]Channel Link: [/]{video_info["channel"]["link"]}\n[green bold]Description: \n[/]{video_info["description"]}'
),
justify="center",
)
play_video = Prompt.ask(
"Continue to Play the Video with mpv[violet](mpv)[/] or open embeded[violet](w)[/] or open in youtube[violet](yt)[/] or quit[violet](q)[/]",
choices=["mpv", "w", "yt", "quit"],
default="mpv",
)
if play_video == "mpv":
with Progress() as progress:
task1 = progress.add_task(
"[green]Loading Player...", total=1000
)
while not progress.finished:
time.sleep(0.01)
progress.update(task1, advance=5)
try:
os.system(
f'mpv --fullscreen --no-terminal --title="youtube - Playing {video_info["title"]} from {video_info["channel"]["name"]}" {video_info["link"]}'
)
except:
webbrowser.open(
f'https://www.youtube-nocookie.com/embed/{video_info["id"]}'
)
if play_video == "w":
try:
webbrowser.open(
f'https://www.youtube-nocookie.com/embed/{video_info["id"]}'
)
except:
webbrowser.open(f'https://youtu.be/{video_info["id"]}')
if play_video == "yt":
webbrowser.open(f'https://youtu.be/{video_info["id"]}')
if play_video == "quit":
quit()
quit()
custom_play_search = CustomSearch(
custom_play_search_term, VideoSortOrder.relevance, limit=1
)
custom_play_search_content = custom_play_search.result()
console.print(
Panel(
f"Details for [red]{custom_play_search_term.capitalize()}[/]'s video"
),
justify="center",
)
console.print(
Panel(
f'[green bold]Most Relevant Video: [/]{custom_play_search_content["result"][0]["title"]}\n[green bold]Url: [/]{custom_play_search_content["result"][0]["link"]}\n[green bold]Channel: [/]{custom_play_search_content["result"][0]["channel"]["name"]}\n[green bold]Duration: [/]{custom_play_search_content["result"][0]["duration"]}\n[green bold]Released: [/]{custom_play_search_content["result"][0]["publishedTime"]}\n[green bold]Views: [/]{custom_play_search_content["result"][0]["viewCount"]["short"]}\n[green bold]Description: [/]{custom_play_search_content["result"][0]["descriptionSnippet"][0]["text"]}'
),
justify="center",
)
play_video = Prompt.ask(
"Continue to Play the Video with mpv[violet](mpv)[/] or open embeded[violet](w)[/] or open in youtube[violet](yt)[/] or quit[violet](q)[/]",
choices=["mpv", "w", "yt", "q"],
default="mpv",
)
if play_video == "mpv":
with Progress() as progress:
task1 = progress.add_task("[green]Loading Player...", total=1000)
while not progress.finished:
time.sleep(0.01)
progress.update(task1, advance=5)
try:
os.system(
f'mpv --fullscreen --no-terminal --title="youtube - Playing {custom_play_search_content["result"][0]["title"]} from {custom_play_search_content["result"][0]["channel"]["name"]}" {custom_play_search_content["result"][0]["link"]}'
)
except:
webbrowser.open(
f'https://www.youtube-nocookie.com/embed/{custom_play_search_content["result"][0]["id"]}'
)
if play_video == "w":
try:
webbrowser.open(
f'https://www.youtube-nocookie.com/embed/{custom_play_search_content["result"][0]["id"]}'
)
except:
webbrowser.open(
f'https://youtu.be/{custom_play_search_content["result"][0]["id"]}'
)
if play_video == "yt":
webbrowser.open(
f'https://youtu.be/{custom_play_search_content["result"][0]["id"]}'
)
if play_video == "q":
quit()
quit()
if args.info:
video_url = args.search_term
video_info = Video.getInfo(video_url)
console.print(
Panel(
f'Details for [red]{video_info["channel"]["name"].capitalize()}[/]\'s video'
),
justify="center",
)
console.print(
Panel(
f'[cyan]{video_info["title"]}[/]\n\n[green bold]Url: [/]{video_info["link"]}\n[green bold]View Count: [/]{video_info["viewCount"]["text"]}\n[green bold]Channel: [/]{video_info["channel"]["name"]}\n[green bold]Channel Link: [/]{video_info["channel"]["link"]}\n[green bold]Description: \n[/]{video_info["description"]}'
),
justify="center",
)
quit()
try:
table = Table(
title=Panel(f"Results for [red]{search_term.capitalize()}"),
show_header=True,
header_style="bold green",
)
table.add_column("Released", style="dim", width=20)
table.add_column("Title", style="yellow")
table.add_column("Channel", style="cyan")
table.add_column("Url", no_wrap=True, style="dim blue")

results = YoutubeSearch(search_term, max_results=20).to_dict()
for i in results:
video_url_for_table = f'https://youtu.be/{i["id"]}'
table.add_row(
i["publish_time"],
i["title"],
i["channel"],
video_url_for_table,
)
console.print(table)
except:
for i in results:
print(
f'\n________________________________________\n{i["title"]}\n {i["publish_time"]}\t {i["channel"]}\t {i["duration"]}\t {i["views"]}\n Video Url: https://youtube.com{i["url_suffix"]}\n________________________________________'
)
print("Unable to use rich, use pip install rich and try again.")

console.print("\n\t\t:compass:Youtube Search\n", style="bold red", justify="center")
term_to_search = args.search_term
search_yt(term_to_search)
50 changes: 50 additions & 0 deletions jarviscli/tests/test_youtube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import unittest

import youtube_search
import youtubesearchpython
from plugins import youtube
from tests import PluginTest
from youtubesearchpython import (
ChannelSearch,
ChannelsSearch,
CustomSearch,
Search,
Video,
VideoSortOrder,
)


class YouTubeTest(PluginTest):
def setUp(self):
self.youtube = self.load_plugin(youtube.youtube)

def test_viewCount_one(self):
test_input = "hello"
expected_output = "Adele - Hello (Official Music Video)"

customSearch = CustomSearch(test_input, VideoSortOrder.view, limit=1)
latest_video = customSearch.result()
returned_output = latest_video["result"][0]["title"]
self.assertEqual(returned_output, expected_output)

def test_viewCount_two(self):
test_input = "messi"
expected_output = "Rare Messi Moments"

customSearch = CustomSearch(test_input, VideoSortOrder.view, limit=1)
latest_video = customSearch.result()
returned_output = latest_video["result"][0]["title"]
self.assertEqual(returned_output, expected_output)

def channel_info_test(self):
test_input = "Marques Brownlee"
expected_output = "https://www.youtube.com/@mkbhd"

channelsSearch = ChannelsSearch(test_input, limit=1)
channelsSearch_content = channelsSearch.result()
returned_output = channelsSearch_content["result"][0]["link"]
self.assertEqual(self.history_say().last_text(), expected_output)


if __name__ == "__main__":
unittest.main()