New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details โ†’ โ†’
Socket
Book a DemoSign in
Socket

grabify-cli

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

grabify-cli - pypi Package Compare versions

Comparing version
1.0.1
to
1.1.0
+12
grabify/__init__.py
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
__version__ = "1.1.0"
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import sys
import click
from .cli import grabify
def main() -> click.Group:
"""Grabify entry point"""
return grabify()
if __name__ == "__main__":
sys.exit(main()) # type: ignore
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import click
import requests
from bs4 import BeautifulSoup
from rich.console import Console
from . import __version__
from .config import cfg
from .utils import get_data_dict, save, theme
console = Console(theme=theme)
@click.group("grabify")
@click.version_option(__version__, "-v", "--version")
def grabify() -> None:
"""A command-line tool that allows you to download
artwork and metadata from Spotify tracks and albums.
"""
@grabify.group("config")
def _config() -> None:
"""Manage config settings"""
pass
@_config.command("set")
@click.argument("key")
@click.argument("value")
def _set(key, value) -> None:
"""Set config value"""
try:
if key not in cfg.to_dict():
return console.print(f"[err]โœ–[/] No '{key}' found in the config.")
cfg.set(key, value)
console.print(f"[ok]โœ”[/] Config updated! '{key}' is set to '{value}'")
except Exception as err:
console.print(f"[err]โœ–[/] Unknown error: {err}")
@_config.command("view")
def _view() -> None:
"""View config values"""
console.print(f"Config path: {cfg._filepath}\n")
console.print(cfg.to_str())
@_config.command("reset")
def _reset() -> None:
"""Restore default settings"""
cfg.create()
console.print("[ok]โœ”[/] Config restored to default settings")
@grabify.command("art")
@click.argument("url")
@click.option("--path", "-p", help="Download path", default=cfg.get("download_path"))
def _art(url, path) -> None:
"""Downloads album/playlist/track artwork"""
try:
image_url = ""
name = ""
response = requests.get(url, timeout=60)
soup = BeautifulSoup(response.text, features="lxml")
for meta in soup.find_all("meta"):
if meta.get("property") == "og:title":
name = meta.get("content")
if meta.get("property") == "og:image":
image_url = meta.get("content")
if None in (image_url, name):
console.print("[err]โœ–[/] Failed to fetch data")
saved_path = save(path, name, image_url=image_url)
console.print(f"[ok]โœ”[/] Saved to {saved_path}")
except requests.exceptions.MissingSchema:
console.print("[err]โœ–[/] Incorrect URL")
except requests.exceptions.Timeout:
console.print("[err]โœ–[/] Connection timed out, try again later")
@grabify.command("data")
@click.argument("url")
@click.option("--path", "-p", help="Download path", default=cfg.get("download_path"))
def _data(url: str, path: str) -> None:
"""Downloads album/playlist/track metadata"""
try:
name = ""
image_url = ""
desc = ""
_type = ""
raw_data = ""
response = requests.get(url, timeout=60)
soup = BeautifulSoup(response.text, features="lxml")
for meta in soup.find_all("meta"):
if meta.get("property") == "og:title":
name = meta.get("content")
if meta.get("property") == "og:image":
image_url = meta.get("content")
if meta.get("property") == "og:description":
raw_data = meta.get("content")
if meta.get("property") == "og:type":
_type = meta.get("content")
if None in (image_url, name, desc):
console.print("[err]โœ–[/] Failed to fetch data")
data = get_data_dict(raw_data, _type, name, image_url)
if cfg.get("format_filenames") is True:
name = name.lower().replace(" ", "_")
saved_path = save(path, name, json_data=data)
console.print(f"[ok]โœ”[/] Saved to {saved_path}")
except requests.exceptions.MissingSchema:
console.print("[err]โœ–[/] Incorrect URL")
except requests.exceptions.Timeout:
console.print("[err]โœ–[/] Connection timed out, try again later")
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import json
import os
from pathlib import Path
class Config:
def __init__(self) -> None:
self._path = os.getenv('LOCALAPPDATA') + "\\Grabify"
self._filepath = self._path + "\\settings.json"
self._download_path = (Path.home() / "Downloads\\Grabify").resolve()
self._default_config = {
"download_path": str(self._download_path),
"format_filenames": True,
}
if not os.path.exists(self._path):
self.create()
def create(self) -> None:
os.makedirs(self._path, exist_ok=True)
with open(self._filepath, "w") as file:
json.dump(self._default_config, file)
def set(self, key, value) -> None:
with open(self._filepath, "r") as file:
data = json.load(file)
data[key] = value
data.update()
with open(self._filepath, "w") as file:
json.dump(data, file)
def get(self, key) -> None:
with open(self._filepath, "r") as file:
data = json.load(file)
return data[key]
def to_dict(self) -> dict:
with open(self._filepath, "r") as file:
return json.load(file)
def to_str(self) -> str:
data = self.to_dict()
res = ""
for key in data.keys():
value = data[key]
res += f"{key}: {value}\n"
return res
cfg = Config()
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import json
import os
from pathlib import Path
from typing import Any, Optional, Union
import requests
from rich.theme import Theme
theme = Theme(
{
"info": "bold blue",
"warn": "bold yellow",
"err": "bold red",
"ok": "bold green",
}
)
def uniquify(path: str) -> str:
"""
Ensure a filename is unique by adding a number to the end if necessary.
This is useful for generating filenames that are unique across the filesystem.
"""
base, ext = os.path.splitext(path)
counter = 1
while os.path.exists(path):
path = f"{base}_{counter}{ext}"
counter += 1
return path
def save(
path: str,
filename: str,
image_url: Optional[str] = None,
json_data: Optional[dict] = None,
) -> Union[str, Any]:
"""
Save file to path. If image_url is provided it will be downloaded
and saved as jpg file.
"""
dirc = str(Path(path).resolve()) + os.sep
os.makedirs(dirc, exist_ok=True)
ext = ".jpg" if image_url else ".json"
dist = uniquify(dirc + filename + ext)
if image_url:
data = requests.get(image_url, timeout=60).content
with open(dist, "wb+") as file:
file.write(data)
else:
data = json.dumps(json_data)
with open(dist, "w+", encoding="utf-8") as file:
file.write(data)
return dist
def get_data_dict(raw_data, _type, name, image_url) -> dict:
"""
Converts data to dict. This is a helper function to make it easier to use in tests
"""
raw_data = str(raw_data).split(" ยท ")
songs = int(raw_data[-1].replace("songs", "").replace(".", ""))
data = {
"name": name,
"image_url": image_url,
"type": _type,
"songs": songs,
}
if _type != "music.playlist":
data.update({"year": raw_data[2], "author": raw_data[0]})
if _type not in ("music.playlist", "music.song"):
data.update({"songs": songs})
if _type == "music.song":
del data["songs"]
return data
+1
-1
Metadata-Version: 2.1
Name: grabify-cli
Version: 1.0.1
Version: 1.1.0
Summary: ๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify tracks and albums without authentication.

@@ -5,0 +5,0 @@ Project-URL: Homepage, https://github.com/woidzero/grabify

@@ -38,6 +38,6 @@ [build-system]

[project.scripts]
grabify = "src.grabify_cli.__main__:main"
grabify = "grabify.__main__:main"
[tool.hatch.version]
path = "src/grabify_cli/__init__.py"
path = "grabify/__init__.py"

@@ -74,4 +74,1 @@ [tool.black]

known-first-party = ["grabify"]
[tool.ruff.flake8-tidy-imports]
ban-relative-imports = "all"
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
__version__ = "1.0.1"
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import sys
import click
from src.grabify_cli.cli import COMMANDS, grabify
for cmd in COMMANDS:
grabify.add_command(cmd)
def main() -> click.Group:
"""Entry point for grabify."""
return grabify()
if __name__ == "__main__":
sys.exit(main()) # type: ignore
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import click
import requests
from bs4 import BeautifulSoup
from rich.console import Console
from . import __version__
from .config import DEFAULT_PATH
from .utils import get_data_dict, save, theme
console = Console(theme=theme)
@click.group("grabify")
@click.version_option(__version__, "-V", "--version")
def grabify() -> None:
"""A command-line tool that allows you to download
artwork and metadata from Spotify tracks and albums.
"""
@click.command("art")
@click.argument("url")
@click.option("--path", "-p", help="Provide download path", default=DEFAULT_PATH)
def _art(url, path) -> None:
"""Downloads album/playlist/track artwork"""
try:
image_url = ""
name = ""
response = requests.get(url, timeout=60)
soup = BeautifulSoup(response.text, features="lxml")
for meta in soup.find_all("meta"):
if meta.get("property") == "og:title":
name = meta.get("content")
if meta.get("property") == "og:image":
image_url = meta.get("content")
if None in (image_url, name):
console.print("[err]โœ–[/] Failed to fetch data")
saved_path = save(path, name, image_url=image_url)
console.print(f"[ok]โœ”[/] Saved to {saved_path}")
except requests.exceptions.MissingSchema:
console.print("[err]โœ–[/] Incorrect URL")
except requests.exceptions.Timeout:
console.print("[err]โœ–[/] Connection timed out, try again later")
@click.command("data")
@click.argument("url")
@click.option("--path", "-p", help="Set download path", default=DEFAULT_PATH)
def _data(url: str, path: str) -> None:
"""Downloads album/playlist/track metadata"""
try:
name = ""
image_url = ""
desc = ""
_type = ""
raw_data = ""
response = requests.get(url, timeout=60)
soup = BeautifulSoup(response.text, features="lxml")
for meta in soup.find_all("meta"):
if meta.get("property") == "og:title":
name = meta.get("content")
if meta.get("property") == "og:image":
image_url = meta.get("content")
if meta.get("property") == "og:description":
raw_data = meta.get("content")
if meta.get("property") == "og:type":
_type = meta.get("content")
if None in (image_url, name, desc):
console.print("[err]โœ–[/] Failed to fetch data")
data = get_data_dict(raw_data, _type, name, image_url)
saved_path = save(path, name.lower().replace(" ", "_"), json_data=data)
console.print(f"[ok]โœ”[/] Saved to {saved_path}")
except requests.exceptions.MissingSchema:
console.print("[err]โœ–[/] Incorrect URL")
except requests.exceptions.Timeout:
console.print("[err]โœ–[/] Connection timed out, try again later")
COMMANDS = (_art, _data)
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
from pathlib import Path
DEFAULT_PATH = (Path.home() / "Downloads\\grabify").resolve()
"""
Grabify
~~~~~~~~~~~~~~~~~~~
๐ŸŽผ A command-line tool that allows you to download artwork and metadata from Spotify
tracks and albums without authentication.
:copyright: (c) 2023 woidzero
:license: MIT, see LICENSE for more details.
"""
import json
import os
from pathlib import Path
from typing import Any, Optional, Union
import requests
from rich.theme import Theme
theme = Theme(
{
"info": "bold blue",
"warn": "bold yellow",
"err": "bold red",
"ok": "bold green",
}
)
def uniquify(path: str) -> str:
"""
Ensure a filename is unique by adding a number to the end if necessary.
This is useful for generating filenames that are unique across the filesystem.
"""
base, ext = os.path.splitext(path)
counter = 1
while os.path.exists(path):
path = f"{base}_{counter}{ext}"
counter += 1
return path
def save(
path: str,
filename: str,
image_url: Optional[str] = None,
json_data: Optional[dict] = None,
) -> Union[str, Any]:
"""
Save file to path. If image_url is provided it will be downloaded
and saved as jpg file.
"""
dirc = str(Path(path).resolve()) + os.sep
os.makedirs(dirc, exist_ok=True)
ext = ".jpg" if image_url else ".json"
dist = uniquify(dirc + filename + ext)
if image_url:
data = requests.get(image_url, timeout=60).content
with open(dist, "wb+") as file:
file.write(data)
else:
data = json.dumps(json_data)
with open(dist, "w+", encoding="utf-8") as file:
file.write(data)
return dist
def get_data_dict(raw_data, _type, name, image_url) -> dict:
"""
Converts data to dict. This is a helper function to make it easier to use in tests
"""
raw_data = str(raw_data).split(" ยท ")
songs = int(raw_data[-1].replace("songs", "").replace(".", ""))
data = {
"name": name,
"image_url": image_url,
"type": _type,
"songs": songs,
}
if _type != "music.playlist":
data.update({"year": raw_data[2], "author": raw_data[0]})
if _type not in ("music.playlist", "music.song"):
data.update({"songs": songs})
if _type == "music.song":
del data["songs"]
return data