#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p python3 -p python3.pkgs.requests -p sane-scripts.lib.bt
# vim: set filetype=python :
"""
sane-bt-add: instruct servo to download or rename some torrent.

to rename an existing torrent, just invoke sane-bt-add as if it were a new torrent,
but use the numeric ID from sane-bt-show instead of a magnet: or .torrent file.
"""

import argparse
import logging
import requests
import tempfile

from requests.exceptions import InvalidSchema

from sane_bt import MediaMeta, TransmissionApi

logger = logging.getLogger(__name__)

# TODO: handle 'InvalidSchema's when kat.ph redirects directly to the magnet:
# 
# class MagnetAdapter:
#     def send(self, req, **kwargs):
#         resp = requests.Response()
#         resp.history = [req.url]
#         return resp
# s = requests.session()
# s.mount('magnet:', MagnetAdapter())
# resp = s.request('GET', uri)
# resp.history[-1]  # contains the magnet: URI, if everything's proper
# except i think history gets overwritten, so may need to assign a different field

def resolve_torrent(uri: str) -> str:
    """
    given a URI, coerce it into something native to transmission
    i.e. magnet: or .torrent.
    """
    if uri.startswith("http://") or uri.startswith("https://"):
        logger.info(f"downloading remote torrent data: {uri}")
        try:
            response = requests.get(uri)
        except InvalidSchema as e:
            # sometimes the URI resolves to a magnet: link (popular with KAT)
            # that's *FINE*, unfortunately `requests` library gives us no way to access that link except by parsing the error message.
            # alternatively i could install some special requests adapter that handles the magnet: schema.
            logger.debug(f"URL resolution error: {e}")
            if len(e.args) == 1 and "magnet:" in e.args[0]:
                uri = e.args[0].replace("No connection adapters were found for ", "")
                uri = uri.strip("'")
                if not uri.startswith("magnet:"): raise
                logger.info(f"resolved torrent to {uri}")
            else:
                raise
        else:
            # N.B.: without `delete=False`, file gets deleted when the function returns.
            # could work around this, but it's nice to keep the file around anyway for troubleshooting
            f = tempfile.NamedTemporaryFile(suffix=".torrent", delete=False)
            f.write(response.content)
            uri = f.name

    if not (uri.startswith("magnet:") or uri.endswith(".torrent")):
        logger.warning(f"unknown type for torrent URI: {uri}")

    return uri


def main():
    logging.basicConfig()
    logging.getLogger().setLevel(logging.INFO)

    parser = argparse.ArgumentParser(description=__doc__)
    TransmissionApi.add_arguments(parser)
    MediaMeta.add_arguments(parser)
    parser.add_argument("torrent", help="file path or URI to torrent (magnet, https)")

    args = parser.parse_args()
    meta = MediaMeta.from_arguments(args)
    bt_api = TransmissionApi.from_arguments(args)
    torrent = args.torrent.strip()

    torrent = resolve_torrent(torrent)
    bt_api.add_or_move_torrent(meta, torrent)

if __name__ == "__main__":
    main()
