{"id":13433803,"url":"https://github.com/miraclx/freyr-js","last_synced_at":"2025-05-13T23:09:46.269Z","repository":{"id":37050973,"uuid":"242945896","full_name":"miraclx/freyr-js","owner":"miraclx","description":"A tool for downloading songs from music streaming services like Spotify and Apple Music.","archived":false,"fork":false,"pushed_at":"2025-05-02T23:20:28.000Z","size":3533,"stargazers_count":1895,"open_issues_count":86,"forks_count":122,"subscribers_count":25,"default_branch":"master","last_synced_at":"2025-05-10T06:04:03.504Z","etag":null,"topics":["album","album-art","apple-music","artist","audio","deezer","download","itunes","m4a","m4a-format","mpeg-4","music","music-streaming","nodejs","playlist","spotify","spotify-api","spotify-web-api","track","youtube"],"latest_commit_sha":null,"homepage":"https://git.io/freyr-js","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/miraclx.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"custom":["https://commerce.coinbase.com/checkout/466d703a-fbd7-41c9-8366-9bdd3e240755"],"ko_fi":"miraclx","liberapay":"miraclx","patreon":"miraclx"}},"created_at":"2020-02-25T08:16:17.000Z","updated_at":"2025-05-09T13:27:23.000Z","dependencies_parsed_at":"2023-10-11T05:41:32.043Z","dependency_job_id":"a9c01359-a06c-406f-89f7-e99952006e21","html_url":"https://github.com/miraclx/freyr-js","commit_stats":{"total_commits":1227,"total_committers":12,"mean_commits":102.25,"dds":"0.16788916055419723","last_synced_commit":"559f2bf219b06100391c8b5d0aa251c4df2ba186"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miraclx%2Ffreyr-js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miraclx%2Ffreyr-js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miraclx%2Ffreyr-js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miraclx%2Ffreyr-js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miraclx","download_url":"https://codeload.github.com/miraclx/freyr-js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254042230,"owners_count":22004871,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["album","album-art","apple-music","artist","audio","deezer","download","itunes","m4a","m4a-format","mpeg-4","music","music-streaming","nodejs","playlist","spotify","spotify-api","spotify-web-api","track","youtube"],"created_at":"2024-07-31T02:01:36.602Z","updated_at":"2025-05-13T23:09:41.252Z","avatar_url":"https://github.com/miraclx.png","language":"JavaScript","funding_links":["https://commerce.coinbase.com/checkout/466d703a-fbd7-41c9-8366-9bdd3e240755","https://ko-fi.com/miraclx","https://liberapay.com/miraclx","https://patreon.com/miraclx"],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003c!-- markdownlint-disable MD001 MD007 MD023 MD033 MD041 MD051 --\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/miraclx/freyr-js\"\u003e\n    \u003cimg src=\"https://github.com/miraclx/freyr-js/raw/master/media/logo.gif\" alt=\"FreyrJS - connoisseur of music\"\u003e\n  \u003c/a\u003e\n\n  # Freyr\n\n  \u003ch4\u003e\n    Download songs from Spotify, Apple Music and Deezer.\n  \u003c/h4\u003e\n\n  [![GitHub](https://img.shields.io/badge/by-miraclx-gray\u0026plastic)](https://github.com/miraclx)\n  [![CodeFactor Grade](https://www.codefactor.io/repository/github/miraclx/freyr-js/badge/master)](https://www.codefactor.io/repository/github/miraclx/freyr-js/overview/master)\n  [![License](https://img.shields.io/github/license/miraclx/freyr-js)](https://github.com/miraclx/freyr-js)\n  [![CI checks](https://github.com/miraclx/freyr-js/actions/workflows/tests.yml/badge.svg)](https://github.com/miraclx/freyr-js/actions/workflows/tests.yml)\n\n  [![NPM Downloads](https://badgen.net/npm/dm/freyr)](https://www.npmjs.com/package/freyr)\n  [![Docker Cloud Pull Status](https://img.shields.io/docker/pulls/freyrcli/freyrjs.svg)](https://hub.docker.com/r/freyrcli/freyrjs)\n  [![NodeJS Version](https://img.shields.io/badge/node-%3E%3D%20v16-brightgreen)](https://github.com/miraclx/freyr-js)\n  [![Python Version](https://img.shields.io/badge/python-%3E%3D%20v3.2-blue)](https://github.com/miraclx/freyr-js)\n\n  [![Total Lines Of Code](https://tokei.rs/b1/github/miraclx/freyr-js?category=code)](https://github.com/miraclx/freyr-js)\n  [![GitHub top language](https://img.shields.io/github/languages/top/miraclx/freyr-js)](https://github.com/miraclx/freyr-js)\n  [![GitHub repo size](https://img.shields.io/github/repo-size/miraclx/freyr-js)](https://github.com/miraclx/freyr-js)\n\n  \u003csub\u003eBuilt with ❤︎ by\n  \u003ca href=\"https://github.com/miraclx\"\u003eMiraculous Owonubi\u003c/a\u003e\n\n\u003c/div\u003e\n\n## Demo\n\n[![ASCII Demo](https://github.com/miraclx/freyr-js/raw/master/media/demo.gif)](https://asciinema.org/a/KH5xyBq9G8Wf5Dyvj6AfqXwYr?autoplay=1 \"Click to view ASCII\")\n\n## Overview\n\n### What freyr does\n\nDepending on the URLs you provide freyr, it will;\n\n1. Extract track metadata (`title`, `album`, `artist`, etc.) from the streaming service (Spotify if you provide a Spotify URL).\n2. Then, it queries sources (e.g. YouTube), classifies the results to find you the best sounding, most accurate audio and downloads that in the raw format.\n3. Next, it processes each track, encoding them in an [Apple AAC](https://en.wikipedia.org/wiki/Advanced_Audio_Coding) format (`.m4a` file extension) at a default bitrate of `320kbps`.\n4. Then, it embeds all the metadata and the album art into each track.\n5. And finally, it organizes all the files into a structured library ([example](https://miraclx.github.io/freyr-demo-library/)).\n\n### Metadata Availability\n\nHere's a list of the metadata that freyr can extract from each streaming service:\n\n|      Meta      | Spotify | Apple Music | Deezer |\n| :------------: | :-----: | :---------: | :----: |\n|    `Title`     |    ✔    |      ✔      |   ✔    |\n|    `Artist`    |    ✔    |      ✔      |   ✔    |\n|   `Composer`   |    ✗    |      ✔      |   ✔    |\n|    `Album`     |    ✔    |      ✔      |   ✔    |\n|    `Genre`     |    ✗    |      ✔      |   ✔    |\n| `Track Number` |    ✔    |      ✔      |   ✔    |\n| `Disk Number`  |    ✔    |      ✔      |   ✔    |\n| `Release Date` |    ✔    |      ✔      |   ✔    |\n|    `Rating`    |    ✔    |      ✔      |   ✔    |\n| `Album Artist` |    ✔    |      ✔      |   ✔    |\n|     `ISRC`     |    ✔    |      ✔      |   ✔    |\n|    `Label`     |    ✔    |      ✔      |   ✔    |\n|  `Copyright`   |    ✔    |      ✔      |   ✔    |\n|  `Cover Art`   |    ✔    |      ✔      |   ✔    |\n\n## Support the project\n\n#### Donate via\n\n[![Patreon Donation](https://img.shields.io/badge/Patreon-donate-f96854?logo=patreon)](https://patreon.com/miraclx)\n[![Liberapay receiving](https://img.shields.io/badge/Liberapay-donate-f6c915?logo=liberapay)](https://liberapay.com/miraclx)\n[![Ko-fi Donation](https://img.shields.io/badge/-donate-ff5e5b?logo=Ko-fi\u0026label=Ko-fi)](https://ko-fi.com/miraclx)\n\n#### Crypto\n\n- Via Coinbase (`BTC`, `ETH`, `USDC`, `LTC`, `DAI`, `BCH`):\n\n  - Support us with [`$5`](https://commerce.coinbase.com/checkout/96849d29-e051-4855-8bac-97f3f2e1a7a8) | [`$10`](https://commerce.coinbase.com/checkout/c8901c03-217a-475a-a764-98cdc6f561e9) | [`$15`](https://commerce.coinbase.com/checkout/e9be7d37-1ee7-4cc6-9daf-fde68c0697cc) | [`$20`](https://commerce.coinbase.com/checkout/4254e8a5-2071-445c-a0bd-c43a4e0d09b0)\n  - Donate [anything you want](https://commerce.coinbase.com/checkout/466d703a-fbd7-41c9-8366-9bdd3e240755)\n\n- Or Directly:\n\n  - [![BTC](https://img.shields.io/badge/-Bitcoin-5b5b5b?logo=bitcoin)](https://explorer.btc.com/btc/address/bc1qqe5y9kw7ewne8njdces8e4ajx5u7zhfftdvl33): `bc1qqe5y9kw7ewne8njdces8e4ajx5u7zhfftdvl33`\n  - [![XLM](https://img.shields.io/badge/-Stellar-5b5b5b?logo=stellar)](https://keybase.io/miraclx): `GB6GPPXXJTQ6EFYQQ4PFA4WEAT5G2DIDILOEDLYH76743UUVDDU4KOWY`\n  - [![ZEC](https://img.shields.io/badge/-Zcash-5b5b5b?logo=cash-app\u0026logoColor=ecb127)](https://keybase.io/miraclx): `zs10awcwm4uwpjr3mxxdwe03fda0j0zn95s4hu3qxlvhfajjw8es98ftmpaava7zh735x9s22pan0l`\n\n## Installation\n\n### Manually\n\n\u003cdetails\u003e\n\u003csummary id=\"requirements\"\u003e Requirements \u003c/summary\u003e\n\n  \u003csub\u003e _Hey there, you might want to consider a cleaner and straight-forward installation method, without having to manually setup the requirements. If so, checkout the [Docker installation method](#docker)_ \u003c/sub\u003e\n\n  \u003cdetails\u003e\n  \u003csummary\u003epython \u003e= v3.2\u003c/summary\u003e\n\n  Download for your individual platforms here \u003chttps://www.python.org/downloads/\u003e\n\n  Linux: _(check individual package managers)_\n\n  - Debian: `sudo apt-get install python3.6`\n  - Arch Linux: `sudo pacman -S python`\n  - Android (Termux): `apt install python`\n  - Alpine Linux: `sudo apk add python3`\n\n  \u003c/details\u003e\n\n  \u003cdetails\u003e\n  \u003csummary\u003enodejs \u003e= v16.0.0\u003c/summary\u003e\n\n  Download for your individual platforms here \u003chttps://nodejs.org/en/download/\u003e\n\n  macOS + Linux: [nvm](https://github.com/nvm-sh/nvm) recommended.\n\n  ```bash\n  # install node with this nvm command\n  # freyr works with a minimum of v16\n  $ nvm install --lts\n  ```\n\n  - Android (Termux): `apt install nodejs`\n  - Alpine Linux: `sudo apk add nodejs`\n\n  \u003c/details\u003e\n\n  \u003cdetails\u003e\n  \u003csummary\u003eAtomicParsley \u003e= 20230114\u003c/summary\u003e\n\n  First, download the latest release for your individual platforms here \u003chttps://github.com/miraclx/atomicparsley/releases/latest\u003e\n\n  Then;\n\n  - Windows:\n    - unzip and place the `AtomicParsley.exe` in your `PATH`.\n    - or the `bins/windows` folder of this project directory. Create the folder(s) if they don't exist.\n  - Linux + macOS:\n    - unzip and place the `AtomicParsley` in your `PATH`.\n    - or the `bins/posix` folder of this project directory. Create the folder(s) if they don't exist.\n  - Alternatively:\n    - Debian: `sudo apt-get install atomicparsley`\n    - Arch Linux: `sudo pacman -S atomicparsley`\n    - Android (Termux): `apt install atomicparsley`\n    - Build from source: See [wez/AtomicParsley](https://github.com/miraclx/atomicparsley)\n\n  \u003c/details\u003e\n\n  \u003e _Please note that [YouTube Music](https://music.youtube.com/) must be available in your region for freyr to successfully work, this is because freyr sources raw audio from [YouTube Music](https://music.youtube.com/)._\n\n  ---\n\u003c/details\u003e\n\nFirst start by ensuring all requirements listed above are satisfied. Thereafter, you can use either of these options to install freyr:\n\n- [NPM](https://github.com/npm/cli): `npm install -g freyr`\n- [Yarn](https://github.com/yarnpkg/yarn): `yarn global add freyr`\n\n- \u003cdetails\u003e\n  \u003csummary\u003eOr you can build from source\u003c/summary\u003e\n\n  ```bash\n  git clone https://github.com/miraclx/freyr-js.git freyr\n  cd freyr\n  ```\n\n  | %                 | NPM           | Yarn           |\n  | ----------------- | ------------- | -------------- |\n  | pull dependencies | `npm install` | `yarn install` |\n  | install globally  | `npm link`    | `yarn link`    |\n\n  \u003c/details\u003e\n\n### Docker\n\nFor convenience, we provide [officially prebuilt images](https://hub.docker.com/r/freyrcli/freyrjs/tags?name=latest) (automated builds from this repository) so you can skip the setup and build process and get right into it.\n\nImage Size: [![Docker Image Size](https://img.shields.io/docker/image-size/freyrcli/freyrjs/latest?color=gray\u0026label=%20\u0026logo=docker)](https://hub.docker.com/r/freyrcli/freyrjs/tags?name=latest)\n\n#### Usage (docker)\n\n```bash\ndocker run -it --rm -v $PWD:/data freyrcli/freyrjs [options, arguments and queries...]\n```\n\nYou can also create a handy alias to skip remembering that whole line everytime\n\n```bash\nalias freyr='docker run -it --rm -v $PWD:/data freyrcli/freyrjs'\n```\n\n\u003e The `-v $PWD:/data` part sets the working directory for freyr to the current working directory.\n\u003e For example, you can use `-v ~/Music/freyr:/data` to set the work directory and consequently, default save location to `~/Music/freyr`.\n\u003e\n\u003e Please ensure the folder on the host already exists, create it if not. Otherwise, docker autocreates the folder as root and that causes unpleasant `Permission Denied` issues when you run freyr.\n\n[See [Docker Development](#docker-development)]\n\n## Getting Started\n\n### Usage\n\n```text\nUsage: freyr [options] [query...]\nUsage: freyr [options] [subcommand]\n```\n\n[See [Service Support](#service-support)].\n\n#### Show freyr help and list subcommands\n\n`freyr --help`\n\n#### Get CLI Help\n\n*The `get` subcommand is implicit and default.\n\n```text\nUsage: freyr [options] get [options] [query...]\nUsage: freyr [options] [query...]\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003efreyr get --help\u003c/code\u003e \u003c/summary\u003e\n\n\u003c!-- editorconfig-checker-disable --\u003e\n```console\n    ____\n   / __/_______  __  _______\n  / /_/ ___/ _ \\/ / / / ___/\n / __/ /  /  __/ /_/ / /\n/_/ /_/   \\___/\\__, /_/\n              /____/ v0.10.3\n\nfreyr - (c) Miraculous Owonubi \u003comiraculous@gmail.com\u003e\n------------------------------------------------------\nUsage: freyr get [options] [query...]\n\nDownload music tracks from queries\n\nOptions:\n  -i, --input \u003cFILE\u003e           use URIs found in the specified FILE as queries (file size limit: 1 MiB)\n                               (each query on a new line, use '#' for comments, whitespaces ignored)\n                               (example: `-i queue.txt`)\n  -b, --bitrate \u003cN\u003e            set audio quality / bitrate for audio encoding\n                               (valid: 96,128,160,192,256,320) (default: \"320k\")\n  -n, --chunks \u003cN\u003e             number of concurrent chunk streams with which to download (default: 7)\n  -r, --retries \u003cN\u003e            set number of retries for each chunk before giving up\n                               (`infinite` for infinite) (default: 10)\n  -t, --meta-retries \u003cN\u003e       set number of retries for collating track feeds (`infinite` for infinite) (default: 5)\n  -d, --directory \u003cDIR\u003e        save tracks to DIR/..\n  -D, --check-dir \u003cDIR\u003e        check if tracks already exist in another DIR (repeatable, optionally comma-separated)\n                               (useful if you maintain multiple libraries)\n                               (example: `-D dir1 -D dir2 -D dir3,dir4`)\n  -c, --cover \u003cNAME\u003e           custom name for the cover art, excluding the extension (default: \"cover\")\n  --cover-size \u003cSIZE\u003e          preferred cover art dimensions\n                               (format: \u003cwidth\u003ex\u003cheight\u003e or \u003csize\u003e as \u003csize\u003ex\u003csize\u003e) (default: \"640x640\")\n  -C, --no-cover               skip saving a cover art\n  -S, --sources \u003cSERVICE\u003e      specify a preferred audio source or a `,`-separated preference order\n                               (valid: youtube,yt_music) (prefix with `!` to exclude) (default: \"yt_music\")\n  -l, --filter \u003cMATCH\u003e         filter matches off patterns (repeatable and optionally `,`-separated)\n                               (value omission implies `true` if applicable)\n                               (format: \u003ckey=value\u003e) (example: title=\"when we all fall asleep*\",type=album)\n                               See `freyr help filter` for more information\n  -L, --filter-case            enable case sensitivity for glob matches on the filters\n  -z, --concurrency \u003cSPEC\u003e     key-value concurrency pairs (repeatable and optionally `,`-separated)\n                               (format: \u003c[key=]value\u003e) (key omission implies track concurrency)\n                               (valid(key): queries,tracks,trackStage,downloader,encoder,embedder)\n                               (example: `queries=2,downloader=4` processes 2 CLI queries,\n                               downloads at most 4 tracks concurrently)\n  --gapless                    set the gapless playback flag for all tracks\n  -f, --force                  force overwrite of existing files\n  -o, --config \u003cFILE\u003e          specify alternative configuration file\n  -p, --playlist \u003cFILENAME\u003e    create playlist for all successfully collated tracks\n  -P, --no-playlist            skip creating a playlist file for collections\n  --playlist-dir \u003cDIR\u003e         directory to save playlist file to, if any, (default: tracks base directory)\n  --playlist-noappend          do not append to the playlist file, if any exists\n  --playlist-noescape          do not escape invalid characters within playlist entries\n  --playlist-namespace \u003cSPEC\u003e  namespace to prefix on each track entry, relative to tracks base directory\n                               useful for, but not limited to custom (file:// or http://) entries\n                               (example, you can prefix with a HTTP domain path: `http://webpage.com/music`)\n  --playlist-force-append      force append collection tracks to the playlist file\n  -s, --storefront \u003cCOUNTRY\u003e   country storefront code (example: us,uk,ru)\n  -T, --no-tree                don't organise tracks in directory structure `[DIR/]\u003cARTIST\u003e/\u003cALBUM\u003e/\u003cTRACK\u003e`\n  --cache-dir \u003cDIR\u003e            specify alternative cache directory\n                               `\u003ctmp\u003e` for tempdir, `\u003ccache\u003e` for system cache\n  --rm-cache [RM]              remove original downloaded files in cache directory (default: false)\n  -m, --mem-cache \u003cSIZE\u003e       max size of bytes to be cached in-memory for each download chunk\n  --no-mem-cache               disable in-memory chunk caching (restricts to sequential download)\n  --timeout \u003cN\u003e                network inactivity timeout (ms) (default: 10000)\n  --no-auth                    skip authentication procedure\n  --no-browser                 disable auto-launching of user browser\n  --no-net-check               disable internet connection check\n  --no-bar                     disable the progress bar\n  --atomic-parsley \u003cPATH\u003e      explicit path to the atomic-parsley binary\n  --no-stats                   don't show the stats on completion\n  --pulsate-bar                show a pulsating bar\n  --single-bar                 show a single bar for the download, hide chunk-view\n                               (default when number of chunks/segments exceed printable space)\n  -h, --help                   show this help information\n\nEnvironment Variables:\n  SHOW_DEBUG_STACK             show extended debug information\n  ATOMIC_PARSLEY_PATH          custom AtomicParsley path, alternatively use `--atomic-parsley`\n\nInfo:\n  When downloading playlists, the tracks are downloaded individually into\n  their respective folders. However, a m3u8 playlist file is generated in\n  the base directory with the name of the playlist that lists the tracks\n```\n\u003c!-- editorconfig-checker-enable --\u003e\n\n\u003c/details\u003e\n\n#### Download a Spotify track\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003efreyr spotify:track:5FNS5Vj69AhRGJWjhrAd01\u003c/code\u003e \u003c/summary\u003e\n\n\u003c!-- editorconfig-checker-disable --\u003e\n```console\n    ____\n   / __/_______  __  _______\n  / /_/ ___/ _ \\/ / / / ___/\n / __/ /  /  __/ /_/ / /\n/_/ /_/   \\___/\\__, /_/\n              /____/ v0.10.3\n\nfreyr - (c) Miraculous Owonubi \u003comiraculous@gmail.com\u003e\n-------------------------------------------------------------\nChecking directory permissions...[done]\n[spotify:track:5FNS5Vj69AhRGJWjhrAd01]\n [•] Identifying service...[Spotify]\n [•] Checking authentication...[unauthenticated]\n [Spotify Login]\n  [•] Logging in...[done]\n Detected [track]\n Obtaining track metadata...[done]\n  ➤ Title: Slow Dance\n  ➤ Album: Slow Dance\n  ➤ Artist: AJ Mitchell\n  ➤ Year: 2019\n  ➤ Playtime: 02:58\n [•] Collating...\n • [01 Slow Dance]\n    | ➤ Collating sources...\n    |  ➤ [•] YouTube Music...[success, found 1 source]\n    | ➤ Awaiting audiofeeds...[done]\n    | [✓] Got album art\n    | [✓] Got raw track file\n    | [•] Post Processing...\n [•] Download Complete\n [•] Embedding Metadata...\n  • [✓] 01 Slow Dance\n[•] Collation Complete\n============ Stats ============\n [•] Runtime: [31.7s]\n [•] Total queries: [01]\n [•] Total tracks: [01]\n     » Skipped: [00]\n     ✓ Passed:  [01]\n     ✕ Failed:  [00]\n [•] Output directory: [.]\n [•] Cover Art: cover.png (640x640)\n [•] Total Output size: 7.30 MB\n [•] Total Network Usage: 3.12 MB\n     ♫ Media: 3.02 MB\n     ➤ Album Art: 106.76 KB\n [•] Output bitrate: 320k\n===============================\n```\n\u003c!-- editorconfig-checker-enable --\u003e\n\n\u003c/details\u003e\n\n#### Download an Apple Music album\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003e freyr https://music.apple.com/us/album/im-sorry-im-not-sorry-ep/1491795443 \u003c/code\u003e \u003c/summary\u003e\n\n\u003c!-- editorconfig-checker-disable --\u003e\n```console\n    ____\n   / __/_______  __  _______\n  / /_/ ___/ _ \\/ / / / ___/\n / __/ /  /  __/ /_/ / /\n/_/ /_/   \\___/\\__, /_/\n              /____/ v0.10.3\n\nfreyr - (c) Miraculous Owonubi \u003comiraculous@gmail.com\u003e\n-------------------------------------------------------------\nChecking directory permissions...[done]\n[https://music.apple.com/us/album/im-sorry-im-not-sorry-ep/1491795443]\n [•] Identifying service...[Apple Music]\n [•] Checking authentication...[authenticated]\n Detected [album]\n Obtaining album metadata...[done]\n  ➤ Album Name: I'm Sorry, I'm Not Sorry\n  ➤ Artist: Sody\n  ➤ Tracks: 4\n  ➤ Type: Album\n  ➤ Year: 2020\n  ➤ Genres: Singer/Songwriter, Music\n [•] Collating [I'm Sorry, I'm Not Sorry]...\n  [•] Inquiring tracks...[done]\n   • [01 What We Had]\n      | ➤ Collating sources...\n      |  ➤ [•] YouTube Music...[success, found 4 sources]\n      | ➤ Awaiting audiofeeds...[done]\n      | [✓] Got album art\n      | [✓] Got raw track file\n      | [•] Post Processing...\n   • [02 Reason To Stay]\n      | ➤ Collating sources...\n      |  ➤ [•] YouTube Music...[success, found 6 sources]\n      | ➤ Awaiting audiofeeds...[done]\n      | [✓] Got album art\n      | [✓] Got raw track file\n      | [•] Post Processing...\n   • [03 Nothing Ever Changes]\n      | ➤ Collating sources...\n      |  ➤ [•] YouTube Music...[success, found 4 sources]\n      | ➤ Awaiting audiofeeds...[done]\n      | [✓] Got album art\n      | [✓] Got raw track file\n      | [•] Post Processing...\n   • [04 Love's a Waste]\n      | ➤ Collating sources...\n      |  ➤ [•] YouTube Music...[success, found 4 sources]\n      | ➤ Awaiting audiofeeds...[done]\n      | [✓] Got album art\n      | [✓] Got raw track file\n      | [•] Post Processing...\n [•] Download Complete\n [•] Embedding Metadata...\n  • [✓] 01 What We Had\n  • [✓] 02 Reason To Stay\n  • [✓] 03 Nothing Ever Changes\n  • [✓] 04 Love's a Waste\n[•] Collation Complete\n============ Stats ============\n [•] Runtime: [2m 2.3s]\n [•] Total queries: [01]\n [•] Total tracks: [04]\n     » Skipped: [00]\n     ✓ Passed:  [04]\n     ✕ Failed:  [00]\n [•] Output directory: [.]\n [•] Cover Art: cover.png (640x640)\n [•] Total Output size: 29.79 MB\n [•] Total Network Usage: 13.35 MB\n     ♫ Media: 12.73 MB\n     ➤ Album Art: 619.43 KB\n [•] Output bitrate: 320k\n===============================\n```\n\u003c!-- editorconfig-checker-enable --\u003e\n\n\u003c/details\u003e\n\n#### Download a Deezer Artist\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003e freyr https://www.deezer.com/us/artist/14808825 \u003c/code\u003e \u003c/summary\u003e\n\n\u003c!-- editorconfig-checker-disable --\u003e\n```console\n    ____\n   / __/_______  __  _______\n  / /_/ ___/ _ \\/ / / / ___/\n / __/ /  /  __/ /_/ / /\n/_/ /_/   \\___/\\__, /_/\n              /____/ v0.10.3\n\nfreyr - (c) Miraculous Owonubi \u003comiraculous@gmail.com\u003e\n-------------------------------------------------------------\nChecking directory permissions...[done]\n[https://www.deezer.com/us/artist/14808825]\n [•] Identifying service...[Deezer]\n [•] Checking authentication...[authenticated]\n Detected [artist]\n Obtaining artist metadata...[done]\n  ➤ Artist: Mazie\n  ➤ Followers: 6\n  \u003e Gathering collections...[done]\n [•] Collating...\n  (01) [i think i wanna be alone] (single)\n   [•] Inquiring tracks...[done]\n    • [01 i think i wanna be alone]\n       | ➤ Collating sources...\n       |  ➤ [•] YouTube Music...[success, found 2 sources]\n       | ➤ Awaiting audiofeeds...[done]\n       | [✓] Got album art\n       | [✓] Got raw track file\n       | [•] Post Processing...\n  (02) [no friends] (single)\n   [•] Inquiring tracks...[done]\n    • [01 no friends]\n       | ➤ Collating sources...\n       |  ➤ [•] YouTube Music...[success, found 4 sources]\n       | ➤ Awaiting audiofeeds...[done]\n       | [✓] Got album art\n       | [✓] Got raw track file\n       | [•] Post Processing...\n [•] Download Complete\n [•] Embedding Metadata...\n  • [✓] 01 i think i wanna be alone\n  • [✓] 01 no friends\n[•] Collation Complete\n============ Stats ============\n [•] Runtime: [54.6s]\n [•] Total queries: [01]\n [•] Total tracks: [02]\n     » Skipped: [00]\n     ✓ Passed:  [02]\n     ✕ Failed:  [00]\n [•] Output directory: [.]\n [•] Cover Art: cover.png (640x640)\n [•] Total Output size: 8.47 MB\n [•] Total Network Usage: 3.66 MB\n     ♫ Media: 3.50 MB\n     ➤ Album Art: 157.16 KB\n [•] Output bitrate: 320k\n===============================\n```\n\u003c!-- editorconfig-checker-enable --\u003e\n\n\u003c/details\u003e\n\n#### Batch downloads\n\n##### via Arguments\n\nQueries can be collated to be processed at once.\n\n```bash\nfreyr query1 query2 ... queryN\n```\n\n##### via Batch File\n\nQueries can be batched into a file and loaded all at once with the `-i, --input \u003cFILE\u003e` flag.\nQueries should be on separate lines.\n\nLines starting with a `#` are treated as comments and ignored. comments can also be inlined with everything following the `#` character ignored.\n\n```text\n# ./queue.txt\n\n# Hailee Steinfeld\nhttps://open.spotify.com/track/5Gu0PDLN4YJeW75PpBSg9p # (track) Let Me Go\nhttps://open.spotify.com/track/7GCVboEDzfL3NKp1NrAgHR # (track) Wrong Direction\n\n# (album) Rina Sawayama\nhttps://open.spotify.com/album/3stadz88XVpHcXnVYMHc4J\n```\n\n```bash\nfreyr -i ./queue.txt\n```\n\nUse the [`--help`](#get-cli-help) flag to see full usage documentation.\n\n#### URIs\n\nServices can be queried with short URIs containing the type and ID for the resource.\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003e identifier \u003c/th\u003e\n      \u003cth\u003e \u003c/th\u003e\n      \u003cth\u003e type \u003c/th\u003e\n      \u003cth\u003e \u003c/th\u003e\n      \u003cth\u003e id \u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd rowspan=4\u003e\n        \u003ca href=\"#service-support\"\u003e URI Short Tags \u003c/a\u003e\n      \u003c/td\u003e\n      \u003ctd rowspan=4\u003e : \u003c/td\u003e\n      \u003ctd\u003e track \u003c/td\u003e\n      \u003ctd rowspan=4\u003e : \u003c/td\u003e\n      \u003ctd rowspan=4\u003e ~ \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e album \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e artist \u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e playlist \u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\nUse the `urify` subcommand to parse betweeen URIs and its equivalent URL representation, and vice-versa.\nCreating freyr-compatible queue output.\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003e freyr urify https://open.spotify.com/album/2D23kwwoy2JpZVuJwzE42B --no-header --no-logo --no-tag \u003c/code\u003e \u003c/summary\u003e\n\n```text\nspotify:album:2D23kwwoy2JpZVuJwzE42B\n[+] Urify complete\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003e freyr urify -i queue_of_urls.txt -o queue_of_uris.txt --no-header --no-logo \u003c/code\u003e \u003c/summary\u003e\n\n```text\n[+] Urify complete\nSuccessfully written to [queue_of_uris.txt]\n```\n\n\u003c/details\u003e\n\n[Examples](#ssue)\n\n### Features\n\n- Multi-service support [See [Service Support](#service-support)]\n- Playlist generation (per playlist (default) / per query (optional))\n- Batch download from queue file\n- Simultaneous chunked downloads (powered by [[libxget-js](https://github.com/miraclx/libxget-js)])\n- Efficient concurrency\n- Bitrate specification (valid: 96, 128, 160, 192, 256, 320)\n- Album art embedding \u0026 export\n- Proper track organisation i.e `FOLDER/\u003cArtist Name\u003e/\u003cAlbum Name\u003e/\u003cTrack Name\u003e` ([example](https://miraclx.github.io/freyr-demo-library/))\n- Resilient visual progressbar per track download (powered by [[xprogress](https://github.com/miraclx/xprogress)])\n- Stats on runtime completion\n  - runtime duration\n  - number of successfully processed tracks\n  - output directory\n  - cover art name\n  - total output size\n  - total network usage\n  - network usage for media\n  - network usage for album art\n  - output bitrate\n\n### Configuration\n\n\u003cdetails\u003e\n\u003csummary\u003eUser / Session specific configuration\u003c/summary\u003e\n\nPersistent configuration such as authentication keys and their validity period are stored within a session specific configuration file.\n\nThis configuration file resides within the user config directory per-platform.\n\n- `$HOME/.config/FreyrCLI/d3fault.x4p` for Linux.\n- `$HOME/Library/Preferences/FreyrCLI/d3fault.x4p` for macOS.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary id='project-specific-configuration'\u003eProject specific configuration\u003c/summary\u003e\n\nAll defaults are defined in the [conf.json](https://github.com/miraclx/freyr-js/blob/master/conf.json) file at the root of the project. This file should be of `JSON` format and is to be structured as such.\n\nDo not edit this file directly, instead run freyr once and edit the user specific configuration (see above).\n\n- `server`: \\\u003cobject\\\u003e The server URL configuration same as on an individual services' callback option.\n  - `hostname`: \\\u003cstring\\\u003e\n  - `port`: \\\u003cnumber\\\u003e\n  - `useHttps`: \\\u003cboolean\\\u003e\n- `concurrency`: \\\u003cobject\\\u003e\n  - `queries`: \\\u003cnumber\\\u003e The number of queries to be processed concurrently.\n  - `tracks`: \\\u003cnumber\\\u003e The number of tracks to be actively processed in parallel.\n  - `trackStage`: \\\u003cnumber\\\u003e The number of tracks to concurrently preprocess before being pushed to the main trackQueue.\n  - `downloader`: \\\u003cnumber\\\u003e The number of tracks to be concurrently downloaded in parallel.\n  - `encoder`: \\\u003cnumber\\\u003e The total number of tracks to be concurrently undergo encoding.\n  - `embedder`: \\\u003cnumber\\\u003e The total number of tracks to be concurrently embedded in parallel.\n- `opts`: \\\u003cobject\\\u003e\n  - `netCheck`: \\\u003cboolean\\\u003e Whether or not to check network access at program start.\n  - `attemptAuth`: \\\u003cboolean\\\u003e Whether or not to process authentication.\n  - `autoOpenBrowser`: \\\u003cboolean\\\u003e Whether or not to automatically open user browser.\n- `filters`: \\\u003c[FilterRules](#filterrules)[]\\\u003e Filter rules each track must match to be downloaded.\n- `dirs`: \\\u003cobject\\\u003e\n  - `output`: \\\u003cstring\\\u003e Default download directory. Default: `\".\"`\n  - `check`: \\\u003cstring[]\\\u003e List of directories to check for existing files. Default: `[\".\"]`\n  - `cache`: \\\u003cobject\\\u003e\n    - `path`: \\\u003cstring\\\u003e Path to download pre-processed audio to (`\"\u003ctmp\u003e\"` for tempdir, `\"\u003ccache\u003e\"` for system cache). Default: `\"\u003ccache\u003e\"`\n    - `keep`: \\\u003cstring\\\u003e Whether or not to keep the pre-processed audio. Default: `\"true\"`\n- `playlist`: \\\u003cobject\\\u003e\n  - `always`: \\\u003cboolean\\\u003e Always create playlists for collections and non-collections alike.\n  - `append`: \\\u003cboolean\\\u003e Append non-collection tracks onto the playlist file.\n  - `escape`: \\\u003cboolean\\\u003e Escape `#` characters within playlist entries paths.\n  - `forceAppend`: \\\u003cboolean\\\u003e Force append collection tracks.\n  - `dir`: \\\u003cstring\\\u003e Default playlist save directory.\n  - `namespace`: \\\u003cstring\\\u003e Prefix namespace to prepend to track paths.\n- `image`: \\\u003cobject|number|string\\\u003e An object with fields pertaining to an image's properties or a number defining its size. (\\\u003cwidth\\\u003ex\\\u003cheight\\\u003e or \\\u003csize\\\u003e as \\\u003csize\\\u003ex\\\u003csize\\\u003e)\n  - `width`: \\\u003cnumber|string\\\u003e\n  - `height`: \\\u003cnumber|string\\\u003e\n- `downloader`: \\\u003cobject\\\u003e\n  - `memCache`: \\\u003cboolean\\\u003e Whether or not to use in-memory caching for download chunks.\n  - `cacheSize`: \\\u003cnumber\\\u003e Maximum size of bytes to be cached per download.\n  - `sources`: \\\u003carray\\\u003e Service download sources order.\n    - Freyr would check these download sources in the order which they are defined. Failure to get a query from a source would try the next available source. You can exclude a source by prefixing it with a `!` character.\n    - supported: `youtube`, `yt_music`\n    - default: `[ \"yt_music\", \"youtube\" ]`\n- `services`: \\\u003c[ServiceConfiguration](#service-configuration): object\\\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eExample JSON\u003c/summary\u003e\n\n```json\n{\n  \"server\": {\n    \"hostname\": \"localhost\",\n    \"port\": 36346,\n    \"useHttps\": false\n  },\n  \"image\": {\n    \"width\": 640,\n    \"height\": 640\n  },\n  \"services\": {\n    \"spotify\": {\n      \"clientId\": \"CLIENT_ID\",\n      \"clientSecret\": \"CLIENT_SECRET\",\n      \"refreshToken\": \"OPTIONAL_REFRESH_TOKEN\"\n    },\n    \"apple_music\": {\n      \"storefront\": \"us\"\n    },\n    \"deezer\": {\n      \"retries\": 5\n    }\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003c/details\u003e\n\n### Service Configuration\n\nThe [conf.json](https://github.com/miraclx/freyr-js/blob/master/conf.json) file already includes some API tokens for service authentication and should work right out of the box. [See [Project specific configuration](#project-specific-configuration)]\n\n\u003cdetails\u003e\n\u003csummary\u003eSpotify\u003c/summary\u003e\n\n- `spotify`: \\\u003cobject\\\u003e\n  - `clientId`: \\\u003cstring\\\u003e\n  - `clientSecret`: \\\u003cstring\\\u003e\n  - `refreshToken`: \\\u003cstring\\\u003e\n\nSpotify requires a `clientId` and a `clientSecret` that can be gotten from their developer dashboard.\n\nIf you wish to create and use custom keys, [See [Spotify API Authorization](#spotify-api-authorization)].\n\nAn optional `refreshToken` option can be defined which can be used to authenticate a session without necessarily requesting explicit permissions. The `refreshToken` is already bound to a pre-authenticated account.\n\nAn invalid `refreshToken`, when specified, would fallback to requesting account access which in-turn would request re-authentication of the users' account.\n\n#### Spotify API Authorization\n\n1. Sign in to the [Spotify Dashboard](https://developer.spotify.com/dashboard/)\n2. Click `CREATE A CLIENT ID` and create an app\n3. Now click `Edit Settings`\n4. Add `http://localhost:36346/callback` to the Redirect URIs\n5. Include the `clientId` and the `clientSecret` from the dashboard in the `spotify` object that is a property of the `services` object of the `conf.json` file. [See [Configuration](#configuration)]\n6. You are now ready to authenticate with Spotify!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eApple Music\u003c/summary\u003e\n\n- `apple_music`: \\\u003cobject\\\u003e\n  - `storefront`: \\\u003cstring\\\u003e\n  - `developerToken`: \\\u003cstring\\\u003e\n\nFreyr would automatically fetch a developer token from the Apple Music site, which should suffice for all intents and purposes. But if you prefer to use a custom developer token, please refer to the Apple Music documentation on this topic.\n\nThe `storefront` option defines the default storefront to be used in the absence of a specification.\n\n#### Apple Music API Authorization\n\n[See [Apple Music API: Getting Keys and Creating Tokens](https://developer.apple.com/documentation/applemusicapi/getting_keys_and_creating_tokens)]\n\nAfter successfully acquiring the developer token, include the `developerToken` to the `apple_music` object that's a property of the `services` object in the `conf.json` file. [See [Configuration](#configuration)]\n\nAn expired developer token in the `conf.json` would make freyr fallback to fetching it from the Apple Music site.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003eDeezer\u003c/summary\u003e\n\n- `deezer`: \\\u003cobject\\\u003e\n  - `retries`: \\\u003cnumber\\\u003e\n\nAuthentication unrequired. API is freely accessible.\n\nBecause of the 50 requests / 5 seconds limit enforced on an IP-basis for Deezer's API [See [#32](https://github.com/miraclx/freyr-js/issues/32)],\noccasionally a `Quota limit exceeded` error would be thrown by the API server.\n\nTo combat this, freyr employs request batching, managed delays and finally, retries when things go awry.\n\nYou can configure how many retries you want freyr to make before accepting failure.\n\n\u003c/details\u003e\n\n### Return Codes\n\n- 0: OK\n- 1: Invalid query\n- 2: Invalid flag value\n- 3: Invalid / Inexistent configuration file\n- 4: Network error\n- 5: Error with working directory\n- 6: Failed to initialize a freyr instance\n- 7: An error occurred checking dependency paths\n\n### FilterRules\n\nFilter rules each to be matched against the tracks involved in any operation.\n\nUsed as values to the `-l, --filter` flag or as key-value pairs in the `filters` array of the [configuration file](#project-specific-configuration).\n\n| key            |     syntax    |   description   | examples |\n| -------------- | :-----------: | --------------- | -------- |\n| `id`           |      glob     | Resource ID     | `id=1497949287`, `id=*149` |\n| `uri`          |      glob     | Resource URI    | `uri=\"*:+(track\\|album):*\"` |\n| `title`        |      glob     | Track title     | `title=\"all*good girls*hell\"` |\n| `album`        |      glob     | Track album     | `album=\"when we*fall*do we go*\"` |\n| `artist`       |      glob     | Match an artist | `artist=\"Billie*\"` |   |\n| `trackn`       | [Numeric Range](#ranges) | Match a track number range | `trackn=\"2..5\"`, `trackn=\"4..=5\"` |\n| `type`         |     Static    | `album` \\| `single` \\| `compilation` | `type=single` |\n| `duration`     |  [Timed Range](#timed-ranges)  | Track duration | `duration=\"3s..\"`, `duration=\"2:30..3:00\"`, `duration=\"..=3m\"` |\n| `explicit`     |     Static    | `true` \\| `false` \\| `inoffensive` | `explicit=true`, `explicit=inoffensive` |\n| `album_artist` |      glob     | Album artist | `album_artist=\"Billie Eilish\"` |\n| `isrc`         |      glob     | Track ISRC   | `isrc=USUM71900766` |\n| `label`        |      glob     | Record label | `label=\"*Interscope*\"` |\n| `year`         | [Numeric Range](#ranges) | Release year | `year=2019`, `year=2018..2020` |\n| `diskn`        | [Numeric Range](#ranges) | Disk number  | `diskn=1` |\n| `ntracks`      | [Numeric Range](#ranges) | Number of tracks in the album | `ntracks=10..=14` |\n\n#### Ranges\n\nSyntax: `[a][..][[=]b]`\n\n| Spec    | Match            | Representation |\n| ------- | ---------------- | -------------- |\n| `..`    | `-∞ ... ∞`       | `x`            |\n| `3..7`  | `3, 4, 5, 6`     | `7 \u003e x ≥ 3`    |\n| `3..=7` | `3, 4, 5, 6, 7`  | `7 ≥ x ≥ 3`    |\n| `..3`   | `-∞ ... 0, 1, 2` | `3 \u003e x`        |\n| `..=3`  | `-∞ ... 1, 2, 3` | `3 ≥ x`        |\n| `5..`   | `5, 6, 7 ... ∞`  | `x ≥ 5`        |\n\n#### Timed Ranges\n\nExamples: `duration=60s..=3:40`\n\n| Metric  | Values                   |\n| ------- | ------------------------ |\n| Seconds | `30`, `30s`, `00:30`     |\n| Minutes | `120`, `120s`, `02:00`   |\n| Hours   | `5400`, `5400s`, `01:30` |\n\n#### Previewing filter representation\n\nTo preview filter rules specification, use the `filter` subcommand.\n\n\u003cdetails\u003e\n\u003csummary\u003e \u003ccode\u003e freyr filter title=\"all*good girls*hell\",artist=\"*eilish\",trackn=\"4..=5\" --no-header --no-logo \u003c/code\u003e \u003c/summary\u003e\n\n```text\n[\n  {\n    \"query\": \"*\",\n    \"filters\": {\n      \"title\": \"all*good girls*hell\",\n      \"artist\": \"*eilish\",\n      \"trackn\": \"4..=5\"\n    }\n  }\n]\n```\n\n\u003c/details\u003e\n\n## Service Support\n\n| Service | Track | Album | Artist | Playlist | [URI Short Tags](#uris) |\n| :-----: | :---: | :---: | :----: | :------: | :------------: |\n| [Spotify](https://github.com/miraclx/freyr-js/blob/master/src/services/spotify.js) |   ✔   |   ✔   |    ✔   |     ✔    | `spotify:` |\n| [Apple Music](https://github.com/miraclx/freyr-js/blob/master/src/services/apple_music.js) |   ✔   |   ✔   |    ✔   |     ✔    | `apple_music:` |\n| [Deezer](https://github.com/miraclx/freyr-js/blob/master/src/services/deezer.js) |   ✔   |   ✔   |    ✔   |     ✔    | `deezer:` |\n| YouTube Music (See [#6](https://github.com/miraclx/freyr-js/issues/6)) |   ✗   |   ✗   |    ✗   |     ✗    | ✗ |\n| Tidal (See [#33](https://github.com/miraclx/freyr-js/issues/33)) |   ✗   |   ✗   |    ✗   |     ✗    | ✗ |\n\n\u003cdetails\u003e\n\u003csummary id=\"ssue\"\u003e \u003cstrong\u003e Short Service URI Examples \u003c/strong\u003e \u003c/summary\u003e\n  \u003ctable\u003e\n    \u003cthead\u003e\n      \u003ctr\u003e\n        \u003cth\u003e Service \u003c/th\u003e\n        \u003cth\u003e Resource Type \u003c/th\u003e\n        \u003cth colspan=2\u003e URIS \u003c/th\u003e\n      \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=8\u003e Spotify \u003c/td\u003e\n        \u003ctd rowspan=2\u003e track \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://open.spotify.com/track/127QTOFJsJQp5LbJbu3A1y\"\u003e https://open.spotify.com/track/127QTOFJsJQp5LbJbu3A1y \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e spotify:track:127QTOFJsJQp5LbJbu3A1y \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e album \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://open.spotify.com/album/623PL2MBg50Br5dLXC9E9e\"\u003e https://open.spotify.com/album/623PL2MBg50Br5dLXC9E9e \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e spotify:album:623PL2MBg50Br5dLXC9E9e \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e artist \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://open.spotify.com/artist/6M2wZ9GZgrQXHCFfjv46we\"\u003e https://open.spotify.com/artist/6M2wZ9GZgrQXHCFfjv46we \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e spotify:artist:6M2wZ9GZgrQXHCFfjv46we \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e playlist \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M\"\u003e https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e spotify:playlist:37i9dQZF1DXcBWIGoYBM5M \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=10\u003e Apple Music \u003c/td\u003e\n        \u003ctd rowspan=4\u003e track \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://music.apple.com/us/album/say-so-feat-nicki-minaj/1510821672?i=1510821685\"\u003e https://music.apple.com/us/album/say-so-feat-nicki-minaj/1510821672?i=1510821685 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e apple_music:track:1510821685 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://music.apple.com/us/song/1510821685\"\u003e https://music.apple.com/us/song/1510821685 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e apple_music:track:1510821685 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e album \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://music.apple.com/us/album/birds-of-prey-the-album/1493581254\"\u003e https://music.apple.com/us/album/birds-of-prey-the-album/1493581254 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e apple_music:album:1493581254 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e artist \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://music.apple.com/us/artist/412778295\"\u003e https://music.apple.com/us/artist/412778295 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e apple_music:artist:412778295 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e playlist \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://music.apple.com/us/playlist/todays-hits/pl.f4d106fed2bd41149aaacabb233eb5eb\"\u003e https://music.apple.com/us/playlist/todays-hits/pl.f4d106fed2bd41149aaacabb233eb5eb \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e apple_music:playlist:pl.f4d106fed2bd41149aaacabb233eb5eb \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=8\u003e Deezer \u003c/td\u003e\n        \u003ctd rowspan=2\u003e track \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://www.deezer.com/en/track/642674232\"\u003e https://www.deezer.com/en/track/642674232 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e deezer:track:642674232 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e album \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://www.deezer.com/en/album/99687992\"\u003e https://www.deezer.com/en/album/99687992 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e deezer:album:99687992 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e artist \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://www.deezer.com/en/artist/5340439\"\u003e https://www.deezer.com/en/artist/5340439 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e deezer:artist:5340439 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd rowspan=2\u003e playlist \u003c/td\u003e\n        \u003ctd\u003e URL \u003c/td\u003e\n        \u003ctd\u003e \u003ca href=\"https://www.deezer.com/en/playlist/1963962142\"\u003e https://www.deezer.com/en/playlist/1963962142 \u003c/a\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd\u003e URI \u003c/td\u003e\n        \u003ctd\u003e \u003ccode\u003e deezer:playlist:1963962142 \u003c/code\u003e \u003c/td\u003e\n      \u003c/tr\u003e\n    \u003c/tbody\u003e\n  \u003c/table\u003e\n\n\u003c/details\u003e\n\n## Development\n\n### Manually Building\n\nFeel free to clone and use in adherance to the [license](#license). Pull requests are very much welcome.\n\n```bash\ngit clone https://github.com/miraclx/freyr-js.git freyr\ncd freyr\n```\n\n- If using [NPM](https://github.com/npm/cli):\n\n  ```bash\n  npm install\n\n  # to have access to the freyr command globally\n  npm link\n  ```\n\n- If using [Yarn](https://github.com/yarnpkg/yarn):\n\n  ```bash\n  yarn install\n\n  # to have access to the freyr command globally\n  yarn link\n  ```\n\n### Testing\n\nFreyr comes bundled with a lightweight test suite. See [TEST.md](https://github.com/miraclx/freyr-js/blob/master/TEST.md) for instructions on how to run it.\n\n### Docker Development\n\nWith docker, you can drop into a sandbox that has all the dependencies you need. Without needing to mess around with your host system or install any weird dependencies.\n\nFirst, you need to either build a local docker image or submit a PR and use the corresponding auto-generated image.\n\n#### Building A Local Image\n\nThe default provided [Dockerfile](https://github.com/miraclx/freyr-js/raw/master/Dockerfile) builds minimal alpine images. Average build network usage is ~ 80 MB and disk usage is ~ 180 MB.\n\n```bash\ngit clone https://github.com/miraclx/freyr-js.git freyr\ncd freyr\ndocker build -t freyr-dev .\n```\n\n#### Working With Remote Images\n\nAn alternative to building the docker image locally is to use a remote image. By default, all PRs submitted to this repository get an equivalently tagged docker image for testing.\n\nFor example, the PR #214 has a docker image called `freyrcli/freyrjs-git:pr-214`. And it stays updated with the current state of the branch.\n\nYou can then pull the development image for use locally.\n\n```bash\ndocker pull freyrcli/freyrjs-git:pr-214\n```\n\n---\n\nOnce you have a built development image locally, you're ready to go. You can drop into the container by explicitly defining the entrypoint\n\n```bash\ndocker run -it --entrypoint bash freyr-dev\n\n# Alternatively, create a handy alias\nalias freyrsh='docker run -it --entrypoint bash freyr-dev'\n```\n\n*: don't forget to replace `freyr-dev` with the appropriate image name if you pulled one of the auto-generated remote images.\n\nOptionally, you can use these interesting flags to customize the experience.\n\n- `-h freyr-dev` sets the container hostname to `freyr-dev`\n- `-m 1G` sets the container memory limit\n- `-v $PWD:/data` mounts the current working directory to `/data` within the container.\n- `--cpus 2` limits the container to using 2 CPU cores\n\nThe freyr source would be available in the `/freyr` directory within the container along with a globally registered command `freyr` for calling the script.\n\nFor more information and documentation about docker, please refer to its official site:\n\n- \u003chttps://www.docker.com/\u003e\n- \u003chttps://docs.docker.com/\u003e\n\n## License\n\n[Apache 2.0][license] © **Miraculous Owonubi** ([@miraclx][author-url]) \\\u003c\u003comiraculous@gmail.com\u003e\\\u003e\n\n[license]:  LICENSE \"Apache 2.0 License\"\n[author-url]: https://github.com/miraclx\n\n\u003c!-- [npm-url]: https://npmjs.org/package/freyr\n[npm-image]: https://badgen.net/npm/node/freyr\n[npm-image-url]: https://nodei.co/npm/freyr.png?stars\u0026downloads\n[downloads-url]: https://npmjs.org/package/freyr\n[downloads-image]: https://badgen.net/npm/dm/freyr --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiraclx%2Ffreyr-js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiraclx%2Ffreyr-js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiraclx%2Ffreyr-js/lists"}