首页 > 编程语言 > 如何编写一个简单的 CLI 应用程序来下载、转换视频并将其保存为音频

如何编写一个简单的 CLI 应用程序来下载、转换视频并将其保存为音频

时间:2023-02-13 16:37:59浏览次数:64  
标签:CLI str 音频 value 应用程序 file path config self

您是否一直想知道如何创建一个非常简单的 CLI 应用程序,让您可以从 YouTube 下载视频,将它们转换为音频,然后将它们保存到计算机上的指定文件夹中?在这篇文章中,我想解释一种在 Python 中实现这一点的快速简便的方法,而不是太古怪。

在大多数情况下,我们会坚持使用 Python 生态系统中的原生产品。该项目中唯一的外部库将是​​Pytube​​库和​​Typer​​。

设置

首先,我们需要创建一个文件夹来存放我们的简单项目。之后,我们创建一个虚拟环境并安装我们的需求,在这个例子中就是 Pytube 和 Typer 库,我们就可以开始了。

执行

对于程序设置,我发现以非常简单和可重用的方式构建代码很重要,以便于维护、可转移性和可读性。话虽如此,我们将定义一个配置文件,该文件将包含我们简单的 CLI 工具将具有的基本配置。这将有助于实际定义我们的工具需要的结构配置。

为了实现简单的配置,我们定义了一个配置文件并将下面的代码写入其中。

from dataclasses import dataclass
from typing import TypeVar, Dict, Any, Type
from config.logger import Logger as CustomLogger
from logging import Logger
import os

ConfigClass = TypeVar('ConfigClass', bound='Config')

LOG_FILE = "logfile.log"
#create a new file for every new experiment
if (os.path.exists(LOG_FILE)):
os.remove(LOG_FILE)

setup = {
"VERSION": 1,
"logger": CustomLogger(logger_name="Video-Downloader", log_file=LOG_FILE).get_logger(),
}

@dataclass
class Config:
VERSION: int
logger: Logger

@classmethod
def from_config(cls: Type[ConfigClass], raw_config: Dict[str, Any]) -> ConfigClass:
return cls(**raw_config)

def configure() -> Config:
return Config.from_config(setup)

因此,我们只需定义简单配置的数据类型,在本例中就是您的应用程序和自定义记录器的版本(可以在​​此处​​找到)。

接下来,我们定义应用程序的驱动程序的外观。这应该是应用程序的主要部分,它根据一些提供的或预定义的参数进行实际工作。这应该类似于下面的代码片段。

from .settings import Config
from sources import download

def run(config: Config, command: str, link: str, output_path: str, file_type: str, path: str = None):
if command == "youtube":
download(config=config, output_path=output_path,
link=link, file_type=file_type, path=path
)
// Here you can add additional video sources should you have them
else:
config.logger.error("No valid command selected")
pass

因此,我们导入上面定义的配置文件和另一个简单的下载函数,它执行实际的下载。目前,我们只有 YouTube 是我们视频的唯一来源的情况。根据选择,这可以扩展到其他视频源。

上面导入的下载函数如下:

from pytube import YouTube
from config import Config
from pathlib import Path
from utils import convert_video_to_audio_ffmpeg

def download(config: Config, output_path: str, link: str, file_type: str, path: str = None) -> None:
path = f"{Path.home()}/Desktop/downloads"
# print(*Path(Path.home()).iterdir(), sep="\\n")
if file_type == "mp4":
config.logger.info(f"Downloading file in mp4 format ...")
yt = YouTube(f"<http://youtube.com/watch?v={link}>")
yt.streams.filter(progressive=True, file_extension='mp4').order_by('resolution').desc().first().download(output_path=path, filename=f"{output_path}.{file_type}")
config.logger.info(f"Video download completed")
config.logger.info(f"Converting video to audio ...")
convert_video_to_audio_ffmpeg(path, f"{output_path}.{file_type}", output_path)
config.logger.info(f"Audio convert completed!")

elif file_type == "3gpp":
config.logger.info(f"Downloading file in 3gpp format")
YouTube(f'<https://youtu.be/{link}>').streams.first().download(output_path="~/Desktop", filename=f"{output_path}.{file_type}")
else:
config.logger.error(f"Wrong file extension format provided. Provided value: {file_type}")
raise Exception(f"Wrong file extension format provided. Provided value: {file_type}")

现在,我们需要定义 CLI 应用程序的基本命令。我们从定义命令的回调开始,然后继续处理触发回调的事件。

import typer
from dataclasses import dataclass
import re
import random
import string

@dataclass
class Constants:
app = typer.Typer()
stage_tool_tip = typer.style("DEV or PROD", fg=typer.colors.BRIGHT_GREEN, bold=True, italic=True)
provider_tool_tip = typer.style("YOUTUBE or INSTAGRAM OR FACEBOOK", fg=typer.colors.BRIGHT_GREEN, bold=True, italic=True)
file_type_tool_tip = typer.style("3gpp or mp4. Default value is mp4", fg=typer.colors.BRIGHT_GREEN, bold=True, italic=True)
url_pattern = "^https?:\\/\\/(?:www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_\\+.~#?&\\/=]*)$"

def get_random_string(self, length: int = 10):
combination = string.ascii_lowercase + string.ascii_uppercase + string.digits
return ''.join(random.choice(combination) for i in range(length))

def provider_callback(self, value: str) -> str:
if not value:
raise typer.BadParameter(f"A provider was not provided. Value should be either {self.provider_tool_tip}!")
if value not in ["youtube", "facebook", "instagram"]:
raise typer.BadParameter(f"Invalid value for the provider. Value should be either of {self.provider_tool_tip}!")
return value.lower()

def link_callback(self, value: str) -> str:
if not value:
raise typer.BadParameter(f"A link was not provided!")
if not re.match(self.url_pattern, value):
raise typer.BadParameter(f"Invalid url provided")
m = re.search('v=(.+?)&', value)
if not m:
raise typer.BadParameter("The wrong url format was provided")
return m.group(1)

def file_type_callback(self, value: str) -> str:
if not value:
return "mp4"
if value not in ["3gpp", "mp4"]:
raise typer.BadParameter(f"Invalid url provided. Value should be either of {self.file_type_tool_tip}!")
return value

def output_callback(self, value: str) -> str:
if not value:
return self.get_random_string()
return value


@dataclass
class Downloader(Constants):
def get_provider_options(self):
return typer.Option(
None,
"--provider", "-p",
help="The provider or the video source",
callback=self.provider_callback
)

def get_link_options(self):
return typer.Option(
None,
"--link", "-l",
help="The link to the video source",
callback=self.link_callback
)

def get_file_type_options(self):
return typer.Option(
None,
"--ext", "-x",
help="The prefered file extension to be downloaded",
callback=self.file_type_callback
)

def get_output_options(self):
return typer.Option(
None,
"--output", "-o",
help="The output name of the file to be saved",
callback=self.output_callback
)

在回调中,我们处理来自命令的传入事件,照顾

  • 提供商,在本例中可以是代码示例中的 youtube、Facebook 或 Instagram
  • 视频的链接
  • 文件扩展名
  • 以及下载文件将另存为的文件名。

就是这样;申请完成。

然后可以这样调用应用程序:

python3 main.py youtube -l <youtube-video-link> -o awesome-song

或者以一种非常简单的方式,

python3 main.py youtube -l <youtube-video-link>

最后一个命令将在保存文件时为文件生成一个随机名称。

结论

我们探索了一种创建 CLI 应用程序的非常简单的方法,该应用程序使用视频 URL 下载、转换 YouTube 视频并将其保存为音频文件。这可以扩展到其他视频源。

我们已经设法以一种非常可扩展的方式构建项目,这样我们就可以轻松地集成其他资源而无需付出太多努力。只需要很少的修改就可以满足您可能有的任何其他需求。

整个项目可以​​在这里​​找到。

标签:CLI,str,音频,value,应用程序,file,path,config,self
From: https://blog.51cto.com/u_1213352/6054464

相关文章