Giter Site home page Giter Site logo

redlist's Introduction

[RED]list

Convert Spotify playlists to local m3u's and fill the gaps!

[RED]list is a tool to glue together Spotify, Beets, and [REDACTED].

Installation

[RED]list requires python 3.6+.

[RED]list also expects you to have a populated Beets library. It will use it to find and match your music files.

To install simply run:

pip install git+https://github.com/Laharah/redlist.git

Usage

usage: redlist [options] <playlist>...

Save spotify playlists as m3u and fill in missing songs from [REDACTED]

positional arguments:
  playlist

optional arguments:
  -h, --help            show this help message and exit
  --config CONFIGFILE   Path to configuration file.
  --beets-library BEETS_LIBRARY
                        The beets library to use
  --downloads TORRENT_DIRECTORY
                        Directory new torrents will be saved to (exclusive
                        with --deluge)
  -y                    Assume yes to all queries and do not prompt.
  --deluge              Load torrents directly into deluge
  --deluge-server DELUGE.HOST
                        address of deluge server, (Default: localhost)
  --deluge-port DELUGE.PORT
                        Port of deluge server, (Default: 58846)
  --restrict-album      Only match tracks if they come from the same album.
  --use-fl-tokens       Use freeleach tokens (note: slows torrent download
                        SIGNIFICANTLY).
  --show-config         Dump the current configuration values and exit.
  --overwrite-m3u       If argument is an m3u, overwrite it instead of
                        outputting to playlist dir.
  --no-redact           Do not redact sensitve information when showing
                        config.
  --log-level {CRITICAL,ERROR,WARNING,INFO,DEBUG}
                        Set the log level. (Default: INFO)

Where playlist is a Spotify playlist (uri or url), an m3u, or a csv file (artist, title, album).

[RED]list will use your local beets library (located automatically) and do it's best to match tracks from the playlist to tracks in your library and write the results to m3u. Any missing tracks can then be automatically searched for on [REDACTED] and torrents will be downloaded or, if you use deluge, added to a running deluge instance.

[RED]list can then be re-run any time on the created m3u playlist to re-match any previously missing files.

Security

The First time you run [RED]list you will be prompted to grant it access to both Spotify and [REDACTED].

[REDACTED]

It is recommended that you generate and use an API key for [REDACTED] access. To generate an API Key for [RED]list to use, go to [REDACTED] > User Settings > API Keys. Then copy the generated key and add it into your config file (see below). DO NOT LOSE THIS KEY. Check the 'Confirm API Key' box and then press save profile. Once a key is confirmed it can be used, but cannot be recovered. You will have to make a new key if you lose this one. [RED]list only requires the User and Torrents API scopes. Feel free to disable other API scopes.

If using password authentication, [RED]list will not store your username or password (unless you enter them into your config). It will however store a cookie from [REDACTED] to keep you logged in. This can be disabled in your configuration file.

Spotify

The first time you give [RED]list a Spotify url, you will have to grant it access to read your playlists, even if the playlist is public. This involves visiting a Spotify link [RED]list gives you and pasting back the (broken) URL Spotify sends you to. This URL contains an access code for [RED]list to poll the Spotify API. It does not grant [RED]list permissions to read anything but your playlists. It also allows redlist to create (private) playlists for you (should you want it to). [RED]list stores this api token in the config directory and refreshes and re-uses it for future use.

Configuration

[RED]list has several configuration options. The defaults are shown here:

beets_library: null          # Usually found automatically
beets_match_threshold: 0.3   # maximum difference between tracks to match (lower is stricter)
pinentry: yes                # Use Pinentry to securely get passwords
enable_deluge: no            # Load downloaded torrents into deluge
torrent_directory: null      # Directory save downloaded torrents
m3u_directory: null          # Directory to save processed m3u playlists
restrict_album: no           # Only allow tracks to match if they are from the same album
overwrite_m3u: no            # If argument is m3u, overwrite it instead of saving to m3u_dir
missing_track_playlist: null # set to a value to have redlist ask to create a spotify playlist of missing tracks

redacted:
  disable: no                # Disable [REDACTED] search entirely.
  api_key: null              # Preferred method. Go to User Settings > API Keys and confirm a new key.
  username: null
  password: null
  save_cookies: yes
  use_fl_tokens: no          # Use freeleach tokens (slows downloads SIGNIFICANTLY)
  format_preferences:        # "Format Encoding Media"
    - 'MP3 V0'
    - 'MP3 320'
    - 'FLAC .*'
    - 'MP3 .*'
    - '.*'

deluge:
  host: 'localhost'
  port: 58846
  username: null
  password: null
  add_paused: no

Any of the above settings can be overridden by settings from your own configuration file. To configure [RED]list, you create a file called config.yaml. The location of the file depends on your platform:

  • On Unix-like OSes: ~/.config/redlist/config.yaml.
  • On Windows: %APPDATA%\redlist\config.yaml.
  • On OS X: ~/Library/Application Support/redlist/config.yaml.

You can use the --show-config option at any time to see what your current configuration looks like. You may also override your config file from the command line with the --config option.

Example

The config uses YAML syntax. An example config might look like so:

missing_track_playlist: prompt
enable_deluge: yes
deluge:
    host: example.com
redacted:
    api_key: 7******f.7******************************5
    format_preferences:
        - 'FLAC .* (CD|Vinyl)'
        - 'FLAC (lossless|24bit Lossless)'
        - 'MP3 (V0|320)'
        - '.*'

This will set [RED]list to automatically add torrents to a deluge server running at example.com. By setting missing_track_playlist [RED]list will prompt the user if they want to create a spotify playlist containing tracks that couldn't be found (could be set to yes to do so automatically).

It also specifies the preferred torrent formats. The preferences are listed as regex strings in the preferred order. The regex strings are matched against a string of the format "format encoding media" eg:(MP3 V0 (VBR) Web). The above regex strings can be interpreted as such:

  • 'FLAC .* (CD|Vinyl)': Any FLAC from CD or vinyl media.
  • 'FLAC (lossless|24bit Lossless)': otherwise, a lossless or 24bit lossless FLAC from any media
  • 'MP3 (V0|320)': otherwise, An MP3 encoded at either V0 or 320, from any media
  • '.*': If none of the above can be found, accept whatever is available

note: the regex strings are not case sensitive

[RED]list will only choose torrents that match at least one of your given preferences. This is why you usually want to end your preferences with a permissive rule.

redlist's People

Contributors

laharah avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

redlist's Issues

Escape slashes in playlistnames

Matching track list to beets library...
Finished. There are 205 tracks that could not be matched.
Writing m3u file to /home/bober/redlist/Glitch Hop/Chiptune/Electro Swing clusterfuck.m3u.
ERROR:redlist.__main__:Error Processing https://open.spotify.com/playlist/2b7k0QgxwU7p30TJhgstLM.
Traceback (most recent call last):
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 241, in entry_point
    results.append(loop.run_until_complete(main(splist, options.yes)))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 57, in main
    playlist.create_m3u_from_info(matched, save_path)
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/playlist.py", line 46, in create_m3u_from_info
    with open(output, 'wb') as fout:
FileNotFoundError: [Errno 2] No such file or directory: '/home/bober/redlist/Glitch Hop/Chiptune/Electro Swing clusterfuck.m3u'

If more than one song from the same album script crashs.

When adding a spotify playlist with several songs from the same album Redlist tries to download the same torrent twice, causing an error and crashing the script.

I would expect it to remove duplicate RED torrents, from the queue, or continue disregarding the error.

Deluge: Connected to localhost:58846
ERROR:redlist.__main__:Error Processing https://open.spotify.com/playlist/XXXXXXXXXXXXXXX.
Traceback (most recent call last):
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 220, in entry_point
    results.append(loop.run_until_complete(main(splist, options.yes)))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 135, in main
    await asyncio.gather(*dls)
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 129, in add_torrent
    client.add_torrent_file(filename, data, paused)
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/deluge.py", line 40, in add_torrent_file
    res = self._client.call('core.add_torrent_file', filename, data, options)
  File "/home/bober/redlist/lib/python3.8/site-packages/deluge_client/client.py", line 247, in call
    return self._receive_response(self.deluge_version, self.deluge_protocol_version)
  File "/home/bober/redlist/lib/python3.8/site-packages/deluge_client/client.py", line 226, in _receive_response
    raise exception(exception_msg)
deluge_client.client.AddTorrentError: Torrent already in session (XXXXXXXXXXXXXXXXXXXXXXXXXXXX).
Traceback (most recent call last):
  File "/usr/lib/python3.8/site-packages/deluge/core/rpcserver.py", line 326, in dispatch
    ret = self.factory.methods[method](*args, **kwargs)
  File "/usr/lib/python3.8/site-packages/deluge/core/core.py", line 482, in add_torrent_file
    return self.torrentmanager.add(
  File "/usr/lib/python3.8/site-packages/deluge/core/torrentmanager.py", line 536, in add
    __, add_torrent_params = self._build_torrent_params(
  File "/usr/lib/python3.8/site-packages/deluge/core/torrentmanager.py", line 446, in _build_torrent_params
    raise AddTorrentError('Torrent already in session (%s).' % torrent_id)
deluge.error.AddTorrentError: Torrent already in session (XXXXXXXXXXXXXXXXXXXXXXXXXXXXX).

All Tracks require an artist and a track

Fetching playlist 37i9dQZF1DXd6tJtr4qeot from spotify.
Matching track list to beets library...
Finished. There are 28 tracks that could not be matched.
Writing m3u file to /home/bober/redlist/Punk Essentials.m3u.

The following tracks could not be matched to your beets library:
Foo Fighters - The Colour And The Shape - Monkey Wrench
Pennywise - Land Of The Free? - Fuck Authority
Rancid - Indestructible - Fall Back Down
Bad Religion - Recipe For Hate - American Jesus
Alkaline Trio - Crimson - Mercy Me
Millencolin - Pennybridge Pioneers - No Cigar
Bad Religion - Stranger Than Fiction - 21st Century [Digital Boy]
Sugarcult - Lights Out - Los Angeles
Jimmy Eat World - Bleed American (Deluxe Edition) - The Middle
The Offspring - Rise And Fall, Rage And Grace - You're Gonna Go Far, Kid
Anti-Flag - For Blood And Empire - This Is the End (For You My Friend)
AFI - DECEMBERUNDERGROUND - Miss Murder
NOFX - The War On Errorism - Franco Un-American
The Ataris - So Long, Astoria - The Boys of Summer
Less Than Jake - Hello Rockview - All My Best Friends Are Metalheads
NOFX - White Trash ...... - Bob
Jimmy Eat World - Futures (Deluxe Version) - Pain
Pennywise - Pennywise - Bro Hymn
Rancid - ...And Out Come The Wolves - Ruby Soho
Lagwagon - Let's Talk About Feelings (Reissue) - May 16
Anti-Flag - For Blood And Empire - The Press Corpse
The Distillers - Sing Sing Death House - City Of Angels
Millencolin - Home From Home - Kemp
NOFX - Pump Up The Valuum - Dinosaurs Will Die
Anti-Flag - The Terror State - Turncoat
Alkaline Trio - From Here to Infirmary - Private Eye
Social Distortion - White Light White Heat White Trash - I Was Wrong
Against Me! - New Wave (U.S. Version) - Thrash Unreal

Connecting to [REDACTED]...
SUCCESS!
Begining search for 28 tracks, This may take a while.
[REDACTED]: hit on first try for Pennywise - Land Of The Free? - Fuck Authority
[REDACTED]: hit on first try for Rancid - Indestructible - Fall Back Down
[REDACTED]: hit on first try for Bad Religion - Recipe For Hate - American Jesus
[REDACTED]: hit on first try for Alkaline Trio - Crimson - Mercy Me
[REDACTED]: hit on first try for Millencolin - Pennybridge Pioneers - No Cigar
[REDACTED]: widening search for Bad Religion - Stranger Than Fiction - 21st Century [Digital Boy]...
[REDACTED]: hit on first try for Sugarcult - Lights Out - Los Angeles
[REDACTED]: hit on first try for Foo Fighters - The Colour And The Shape - Monkey Wrench
[REDACTED]: hit on first try for The Offspring - Rise And Fall, Rage And Grace - You're Gonna Go Far, Kid
[REDACTED]: widening search for Anti-Flag - For Blood And Empire - This Is the End (For You My Friend)...
[REDACTED]: hit on first try for AFI - DECEMBERUNDERGROUND - Miss Murder
[REDACTED]: Considering For Blood and Empire: id=1793959 for "This Is the End (For You My Friend)"
[REDACTED]: widening search for NOFX - The War On Errorism - Franco Un-American...
[REDACTED]: widening search for Jimmy Eat World - Bleed American (Deluxe Edition) - The Middle...
[REDACTED]: hit on first try for The Ataris - So Long, Astoria - The Boys of Summer
[REDACTED]: Considering Stranger Than Fiction: id=1698497 for "21st Century [Digital Boy]"
[REDACTED]: widening search for NOFX - White Trash ...... - Bob...
[REDACTED]: Found torrent for "Anti-Flag - For Blood And Empire - This Is the End (For You My Friend)" with 71.2% confidence.
[REDACTED]: hit on first try for Less Than Jake - Hello Rockview - All My Best Friends Are Metalheads
[REDACTED]: Unable to find torrent for Jimmy Eat World - Bleed American (Deluxe Edition) - The Middle
[REDACTED]: Could not find Bleed American (Deluxe Edition), Checking other albums by Jimmy Eat World.
[REDACTED]: hit on first try for Pennywise - Pennywise - Bro Hymn
[REDACTED]: widening search for Jimmy Eat World - Futures (Deluxe Version) - Pain...
[REDACTED]: Found torrent for "Bad Religion - Stranger Than Fiction - 21st Century [Digital Boy]" with 71.4% confidence.
[REDACTED]: Unable to find torrent for NOFX - White Trash ...... - Bob
[REDACTED]: Could not find White Trash ......, Checking other albums by NOFX.
[REDACTED]: widening search for Lagwagon - Let's Talk About Feelings (Reissue) - May 16...
[REDACTED]: hit on first try for Anti-Flag - For Blood And Empire - The Press Corpse
[REDACTED]: Considering White Trash, Two Heebs and a Bean: id=937129 for "Bob"
[REDACTED]: Unable to find torrent for Lagwagon - Let's Talk About Feelings (Reissue) - May 16
[REDACTED]: Could not find Let's Talk About Feelings (Reissue), Checking other albums by Lagwagon.
[REDACTED]: hit on first try for Rancid - ...And Out Come The Wolves - Ruby Soho
[REDACTED]: hit on first try for The Distillers - Sing Sing Death House - City Of Angels
[REDACTED]: Considering Bleed American: id=957163 for "The Middle"
[REDACTED]: Considering The War on Errorism: id=429971 for "Franco Un-American"
[REDACTED]: hit on first try for Millencolin - Home From Home - Kemp
[REDACTED]: hit on first try for NOFX - Pump Up The Valuum - Dinosaurs Will Die
[REDACTED]: Considering Let's Talk About Feelings: id=833343 for "May 16"
[REDACTED]: Unable to find torrent for Jimmy Eat World - Futures (Deluxe Version) - Pain
[REDACTED]: Could not find Futures (Deluxe Version), Checking other albums by Jimmy Eat World.
[REDACTED]: hit on first try for Anti-Flag - The Terror State - Turncoat
[REDACTED]: Found torrent for "Lagwagon - Let's Talk About Feelings (Reissue) - May 16" with 100.0% confidence.
[REDACTED]: Considering Futures: id=2531384 for "Pain"
[REDACTED]: Found torrent for "NOFX - The War On Errorism - Franco Un-American" with 70.3% confidence.
[REDACTED]: Found torrent for "Jimmy Eat World - Futures (Deluxe Version) - Pain" with 100.0% confidence.
[REDACTED]: hit on first try for Alkaline Trio - From Here to Infirmary - Private Eye
[REDACTED]: hit on first try for Social Distortion - White Light White Heat White Trash - I Was Wrong
[REDACTED]: Found torrent for "NOFX - White Trash ...... - Bob" with 100.0% confidence.
[REDACTED]: Considering Bleed American Demos: id=241293 for "The Middle"
ERROR:redlist.__main__:Error Processing https://open.spotify.com/playlist/37i9dQZF1DXd6tJtr4qeot.
Traceback (most recent call last):
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 233, in entry_point
    results.append(loop.run_until_complete(main(splist, options.yes)))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 84, in main
    await asyncio.gather(*tasks.values())
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/redsearch.py", line 88, in find_album
    hit = await search_torrent_groups(track_info,
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/redsearch.py", line 149, in search_torrent_groups
    canidate_info = matching.TrackInfo(title=track_canidate,
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/matching.py", line 28, in __init__
    raise ValueError("All Tracks require an artist and a track")
ValueError: All Tracks require an artist and a track

-y option still prompting user for password

Hi, I only discovered your script recently and absolutely love it. I've been wanting this for a long time.

I have a script calling redlist to update all my playlists. However, redlist always ask for some user input even with the -y option.
Here is my config:

beets_library: /.../musiclibrary2.blb
torrent_directory: .
m3u_directory: /.../playlists_navidrome
pinentry: yes
enable_deluge: no
restrict_album: no
overwrite_m3u: yes

Basically, it tries to connect to [REDACTED] (i'm still confused about what redacted is, is it jackett? or something similar?). But since in my config, I disabled deluge, I don't expect any music search to happen on various trackers. But redlist is prompting me for a username/password.

Connecting to [REDACTED]...
[REDACTED] Username:
Search Canceled.
ERROR:asyncio:Unclosed client session

How can I disable this?

(EDIT: found what redacted is, makes more sense now)

Only downloads 10 torrents at once

Seems that RED blocks the 10th torrent request.

ERROR:redlist.redapi:<CIMultiDictProxy('Server': 'nginx', 'Date': 'Sun, 05 Apr 2020 02:02:14 GMT', 'Content-Type': 'text/html; charset=UTF-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'X-Frame-Options': 'DENY', 'Content-Encoding': 'gzip', 'Strict-Transport-Security': 'max-age=31536000', 'X-Frame-Options': 'DENY')>
ERROR:redlist.__main__:Error Processing https://open.spotify.com/playlist/XXXXXXXXXXXXXXXXXXXXXXX.
Traceback (most recent call last):
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 220, in entry_point
    results.append(loop.run_until_complete(main(splist, options.yes)))
  File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
    return future.result()
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 135, in main
    await asyncio.gather(*dls)
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/__main__.py", line 127, in add_torrent
    filename, data = await api.get_torrent(
  File "/home/bober/redlist/lib/python3.8/site-packages/redlist/redapi.py", line 135, in get_torrent
    raise ValueError("Wrong content-type: {}".format(
ValueError: Wrong content-type: text/html; charset=UTF-8

Can we also do local m3u to Spotify?

For redlist to be a complete solution, I was wondering if it can also do local m3u to Spotify. Redlist already uses Beets library, so we can match the m3u tracks in the beets library and find a match in Spotify.

ERROR:redlist:program pinentry could not be found in path

Whenever i run the command 'redlist', my cmd displays the error: 'ERROR:redlist:program pinentry could not be found in path.', followed by:

Traceback (most recent call last):
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\runpy.py", line 193, in run_module_as_main
"main", mod_spec)
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\runpy.py", line 85, in run_code
exec(code, run_globals)
File "C:\Users\HP\AppData\Local\Programs\Python\Python36-32\Scripts\redlist.exe_main
.py", line 4, in
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\redlist_main
.py", line 17, in
from . import redapi
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\redlist\redapi.py", line 3, in
import aiohttp
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\aiohttp_init_.py", line 6, in
from .client import (
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\aiohttp\client.py", line 36, in
from . import hdrs, http, payload
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\aiohttp\http.py", line 7, in
from .http_parser import (
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\aiohttp\http_parser.py", line 43, in
from .streams import EMPTY_PAYLOAD, StreamReader
File "c:\users\hp\appdata\local\programs\python\python36-32\lib\site-packages\aiohttp\streams.py", line 4, in
from typing import Awaitable, Callable, Deque, Generic, List, Optional, Tuple, TypeVar
ImportError: cannot import name 'Deque'

I tried creating a new config file with the line "pinentry: no", but I'm not sure if I put it in the right directory or if that would even solve my issue.

Please help.

Song matching with wrong artists

Issue

currently, redlist can match a similar song title from the beet library if it's coming from a totally different artist

Example

Let's say we're trying to match the following tune from spotify:

  • Vampire, Performed by Solence

If this tune/artist is missing from the beet library, but a similar title exists, redlist will match with the closest title available, for example:

  • Reggae/Peter Tosh/1987 - No Nuclear War/04 Vampire.mp3

Solution?

We probably should have in the redlist config along the restrict_album option, another one:

  • restrict_artist

I believe that those two options could take a value between 0 and 1 rather than a true/false value. Some artists could be spell differently, especially when there is an artist featuring. By using a value between 0 and 1, some fuzzysearch could maybe be implemented, and this value would be the degree of confidence.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.