#!/usr/bin/env python3

# uget-integrator is a tool to integrate uGet Download manager
# with Google Chrome, Chromium, Vivaldi and Opera in Linux and Windows.

# Copyright (C) 2016  Gobinath

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os
import struct
import sys
import threading
import logging
import json
import urllib
import subprocess
import tempfile
from urllib.parse import urlparse
from urllib.parse import unquote
from urllib.request import urlopen
from os.path import splitext, basename, join, expanduser
from mimetypes import guess_extension

cookie_filepath = join(tempfile.gettempdir(), 'uget_cookie')
urls_filepath = join(tempfile.gettempdir(), 'uget_urls')
UGET_COMMAND = 'uget-gtk'
VERSION = "1.0.0"
creation_flags = 0

logger = logging.getLogger()
# log_file_path = join(expanduser('~'), 'uget-integrator.log')
# logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', filename=log_file_path, filemode='a', level=logging.DEBUG)
logger.propagate = False

# Platform specific configuration
if sys.platform == 'win32':
    # Set the default I/O mode to O_BINARY in windows
    import msvcrt
    msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
    msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
    # CREATE_BREAKAWAY_FROM_JOB
    creation_flags |= 0x01000000


def extract_file_name(url):
    fileName = ''
    if 'googlevideo.com/' in url and '&title=' in url:
        # Youtube video
        logger.debug('Found Youtube video')
        url = urllib.parse.unquote(url)
        url_components = url.split('&')
        for smt in url_components:
            if smt.startswith('title='):
                title = smt.replace('title=', '').replace('+', ' ')
            elif smt.startswith('mime='):
                mime = smt.replace('mime=', '')

        if title:
            fileName = title
            if mime:
                fileName += guess_extension(mime)
            logger.debug('Youtube filename: ' + fileName)
    elif 'www.youtube.com/watch' in url:
        fileName = ''
    else:
        fileName = basename(urlparse(url).path).replace('%20', ' ')

    return fileName


def send_message(message):
    """
    Send a message to the webapp.
    """
    logger.info('Sending message: ' + str(message))
    try:
        # Write message size.
        sys.stdout.buffer.write(struct.pack('I', len(message)))
        # Write the message itself.
        sys.stdout.write(message)
        sys.stdout.flush()
    except Exception as e:
        logger.error('Error in sending message: ' + str(e))


def download_all_links(data):
    """
    Extract all links from the html page and download them.
    """
    urls = data['URL']
    cookie = data['Cookies']
    try:
        logger.debug('Writing links to file')
        with open(urls_filepath, 'w') as url_file:
            url_file.write(urls)

        command = [UGET_COMMAND, "--input-file=" + urls_filepath]
        use_cookie_file = False
        if cookie:
            try:
                with open(cookie_filepath, 'w') as cookie_file:
                    cookie_file.write(cookie)
                use_cookie_file = True
            except Exception:
                pass

        if use_cookie_file:
            command.append("--http-cookie-file=" + cookie_filepath)
        # Pass the parameters to uGet
        subprocess.Popen(command, creationflags=creation_flags).wait()

        if use_cookie_file:
            try:
                os.remove(cookie_filepath)
            except Exception as e:
                pass

        try:
            os.remove(urls_filepath)
        except Exception as e:
            pass
    except Exception as e:
        pass


def read_message():
    """
    Read messages from the webapp.
    """
    logger.info('uget-integrator is reading the message')

    while 1:
        # Read the message length (first 4 bytes).
        text_length_bytes = sys.stdin.buffer.read(4)

        # Unpack message length as 4 byte integer.
        text_length = struct.unpack('i', text_length_bytes)[0]

        logger.debug('Message length: ' + str(text_length))

        # Read the text (JSON object) of the message.
        text = sys.stdin.buffer.read(text_length).decode('utf-8')

        logger.debug('Received message: ' + str(text))

        if text:
            if not 'URL' in text:
                uget_version = subprocess.Popen(
                    [UGET_COMMAND + " --version"], shell=True, stdout=subprocess.PIPE, universal_newlines=True).communicate()[0]
                uget_version = uget_version.replace(
                    'uGet', '').replace('for GTK+', '').strip()
                logger.debug('uGet version: ' + uget_version)
                send_message('{"Status": "Available", "Version": "' +
                             VERSION + '", "Uget": "' + uget_version + '"}')
                return

            send_message('{"Status": "Available", "Version": "' + VERSION + '", "Uget": ""}')
            data = json.loads(text)
            url = data['URL']

            if url != "":
                if data['Batch']:
                    download_all_links(data)
                    return
                use_cookie_file = False
                fileName = data['FileName']
                cookie = data['Cookies']
                referer = data['Referer']
                command = [UGET_COMMAND]
                if cookie:
                    try:
                        with open(cookie_filepath, 'w') as cookie_file:
                            cookie_file.write(cookie)
                        use_cookie_file = True
                    except Exception as e:
                        pass
                if not fileName:
                    fileName = extract_file_name(url)
                else:
                    # Sometimes Firefox sends complete path
                    fileName = basename(fileName)

                # Add the referer url
                if referer:
                    command.append("--http-referer=" + referer)

                # Add the file name
                if fileName:
                    command.append("--filename=" + unquote(fileName))

                # Add the cookie file
                if use_cookie_file:
                    command.append("--http-cookie-file=" + cookie_filepath)

                # Add the url
                command.append(url)

                logger.debug('Execute command: ' + str(command))
                # Pass the parameters to uGet
                subprocess.Popen(command, creationflags=creation_flags).wait()

                if use_cookie_file:
                    try:
                        os.remove(cookie_filepath)
                    except Exception as e:
                        pass

            sys.exit(0)


if __name__ == '__main__':
    read_message()
