Skip to content
Snippets Groups Projects
xdgurl.py 13.2 KiB
Newer Older
akiraohgaki's avatar
akiraohgaki committed
#!/usr/bin/env python

import sys
import os
import json
import urllib
import urlparse
import tempfile
import mimetypes
import subprocess
akiraohgaki's avatar
akiraohgaki committed
import Tkinter
import tkMessageBox

class XdgUrl:
    """Core class of xdgurl"""

    def __init__(self, xdg_url=''):
        self.xdg_url = xdg_url
        self.meta = self.parse()

        self.temp_dir = tempfile.gettempdir()
        self.home_dir = os.path.expanduser('~')
        #self.config_dir = os.path.join(self.home_dir, '.config', 'xdgurl')
        self.data_dir = os.path.join(self.home_dir, '.local', 'share')
        self.kde_data_dir = os.path.join(self.home_dir, '.kde', 'share')

        #self.config = {}

        self.destinations = {
            'downloads': os.path.join(self.home_dir, 'Downloads'),
            'documents': os.path.join(self.home_dir, 'Documents'),
            'pictures': os.path.join(self.home_dir, 'Pictures'),
            'music': os.path.join(self.home_dir, 'Music'),
            'videos': os.path.join(self.home_dir, 'Videos'),
            'wallpapers': os.path.join(self.data_dir, 'wallpapers'),
            'fonts': os.path.join(self.home_dir, '.fonts'),
            'cursors': os.path.join(self.home_dir, '.icons'),
            'icons': os.path.join(self.data_dir, 'icons'),
            'emoticons': os.path.join(self.data_dir, 'emoticons'),
            'themes': os.path.join(self.home_dir, '.themes'),
            'emerald_themes': os.path.join(self.home_dir, '.emerald', 'themes'),
            'enlightenment_themes': os.path.join(self.home_dir, '.e', 'e', 'themes'),
            'enlightenment_backgrounds': os.path.join(self.home_dir, '.e', 'e', 'backgrounds'),
            'fluxbox_styles': os.path.join(self.home_dir, '.fluxbox', 'styles'),
            'pekwm_themes': os.path.join(self.home_dir, '.pekwm', 'themes'),
            'icewm_themes': os.path.join(self.home_dir, '.icewm', 'themes'),
            'plasma_plasmoids': os.path.join(self.data_dir, 'plasma', 'plasmoids'),
            'plasma_look_and_feel': os.path.join(self.data_dir, 'plasma', 'look-and-feel'),
            'plasma_desktopthemes': os.path.join(self.data_dir, 'plasma', 'desktoptheme'),
            'kwin_effects': os.path.join(self.data_dir, 'kwin', 'effects'),
            'kwin_scripts': os.path.join(self.data_dir, 'kwin', 'scripts'),
            'kwin_tabbox': os.path.join(self.data_dir, 'kwin', 'tabbox'),
            'aurorae_themes': os.path.join(self.data_dir, 'aurorae', 'themes'),
            'dekorator_themes': os.path.join(self.data_dir, 'deKorator', 'themes'),
            'qtcurve': os.path.join(self.data_dir, 'QtCurve'),
            'color_schemes': os.path.join(self.data_dir, 'color-schemes'),
            'gnome_shell_extensions': os.path.join(self.data_dir, 'gnome-shell', 'extensions'),
            'cinnamon_applets': os.path.join(self.data_dir, 'cinnamon', 'applets'),
akiraohgaki's avatar
akiraohgaki committed
            'cinnamon_desklets': os.path.join(self.data_dir, 'cinnamon', 'desklets'),
            'nautilus_scripts': os.path.join(self.data_dir, 'nautilus', 'scripts'),
            'amarok_scripts': os.path.join(self.kde_data_dir, 'apps', 'amarok', 'scripts'),
            'yakuake_skins': os.path.join(self.kde_data_dir, 'apps', 'yakuake', 'skins'),
            'cairo_clock_themes': os.path.join(self.home_dir, '.cairo-clock', 'themes')
        }
        self.destinations_alias = {
            'gnome_shell_themes': self.destinations['themes'],
            'cinnamon_themes': self.destinations['themes'],
            'gtk2_themes': self.destinations['themes'],
            'gtk3_themes': self.destinations['themes'],
            'metacity_themes': self.destinations['themes'],
            'xfwm4_themes': self.destinations['themes'],
            'openbox_themes': self.destinations['themes'],
            'kvantum_themes': self.destinations['themes'],
            'compiz_themes': self.destinations['emerald_themes'],
            'beryl_themes': self.destinations['emerald_themes'],
            'plasma4_plasmoids': self.destinations['plasma_plasmoids'],
            'plasma5_plasmoids': self.destinations['plasma_plasmoids'],
            'plasma5_look_and_feel': self.destinations['plasma_look_and_feel'],
            'plasma5_desktopthemes': self.destinations['plasma_desktopthemes'],
            'plasma_color_schemes': self.destinations['color_schemes']
        }
        self.destinations.update(self.destinations_alias)

        self.archive_types = {
            'tar': [
                'application/x-tar',
                'application/x-gzip',
                'application/gzip',
                'application/x-bzip',
                'application/x-bzip2',
                'application/x-xz',
                'application/x-lzma',
                'application/x-lzip',
                'application/x-compressed-tar',
                'application/x-bzip-compressed-tar',
                'application/x-bzip2-compressed-tar',
                'application/x-xz-compressed-tar',
                'application/x-lzma-compressed-tar',
                'application/x-lzip-compressed-tar'
            ],
            'zip': ['application/zip'],
            '7z': ['application/x-7z-compressed'],
            'rar': [
                'application/x-rar',
                'application/x-rar-compressed'
            ]
        }

        #self.config.update(self.read_config('config'))
        #self.destinations.update(self.read_config('destinations'))

    def read_config(self, name):
        path = os.path.join(self.config_dir, name + '.json')
        data = {}
        if os.path.isfile(path):
            f = open(path, 'r')
akiraohgaki's avatar
akiraohgaki committed
            data = json.load(f)
            f.close()
        return data

    def write_config(self, name, data):
        if not os.path.isdir(self.config_dir):
            os.makedirs(self.config_dir)
        path = os.path.join(self.config_dir, name + '.json')
        f = open(path, 'w')
        json.dump(data, f)
        f.close()

    def parse(self):
        meta = {
            'command': 'download',
            'url': '',
            'type': 'downloads',
            'filename': ''
        }

        parse_result = urlparse.urlparse(self.xdg_url)
        query = urlparse.parse_qs(parse_result.query)

        if parse_result.netloc:
            meta['command'] = parse_result.netloc

        if 'url' in query and query['url'][0]:
            meta['url'] = urllib.unquote(query['url'][0])

        if 'type' in query and query['type'][0]:
            meta['type'] = urllib.unquote(query['type'][0])

        if 'filename' in query and query['filename'][0]:
            meta['filename'] = urllib.unquote(query['filename'][0]).split('?')[0]
akiraohgaki's avatar
akiraohgaki committed

        if meta['url'] and not meta['filename']:
            meta['filename'] = os.path.basename(meta['url']).split('?')[0]
akiraohgaki's avatar
akiraohgaki committed

        return meta

    """
    def detect_desktop_environment(self):
        desktop_environment = 'unknown'
        if os.environ.get('KDE_FULL_SESSION') == 'true':
            desktop_environment = 'kde'
        elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
            desktop_environment = 'gnome'
        return desktop_environment
    """

    def install_plasmapkg(self, path, type='plasmoid'):
        status = subprocess.call(['plasmapkg2', '-t', type, '-i', path])
        if status == 0:
            return True
        return False

    def uncompress_archive(self, path, target_dir):
        (mimetype, encoding) = mimetypes.guess_type(path)
        status = None

        if mimetype in self.archive_types['tar']:
            status = subprocess.call(['tar', '-xf', path, '-C', target_dir])
        elif mimetype in self.archive_types['zip']:
            status = subprocess.call(['unzip', '-o', path, '-d', target_dir])
        elif mimetype in self.archive_types['7z']:
            # No space between -o and directory
            status = subprocess.call(['7z', 'x', path, '-o' + target_dir])
        elif mimetype in self.archive_types['rar']:
            status = subprocess.call(['unrar', 'e', path, target_dir])

        if status == 0:
            return True
        return False

    def download(self):
        url = self.meta['url']
        type = self.meta['type']
        filename = self.meta['filename']
        destination = self.destinations[type]

        temp_path = os.path.join(self.temp_dir, filename)
        path = os.path.join(destination, filename)

        print('Retrieving a file from ' + url)
        urllib.urlretrieve(url, temp_path)

        print('Creating a directory ' + destination)
        if not os.path.isdir(destination):
            os.makedirs(destination)

        print('Saving a file to ' + path)
        os.rename(temp_path, path)

        print('Done')

    def install(self):
        url = self.meta['url']
        type = self.meta['type']
        filename = self.meta['filename']
        destination = self.destinations[type]

        temp_path = os.path.join(self.temp_dir, filename)
        path = os.path.join(destination, filename)

        print('Retrieving a file from ' + url)
        urllib.urlretrieve(url, temp_path)

        print('Creating a directory ' + destination)
        if not os.path.isdir(destination):
            os.makedirs(destination)

        print('Installing')
        if (type in ['plasma_plasmoids', 'plasma4_plasmoids', 'plasma5_plasmoids']
        and self.install_plasmapkg(temp_path, 'plasmoid')):
            print('The plasmoid has been installed')
            os.remove(temp_path)
        elif (type in ['plasma_look_and_feel', 'plasma5_look_and_feel']
        and self.install_plasmapkg(temp_path, 'lookandfeel')):
            print('The plasma look and feel has been installed')
            os.remove(temp_path)
        elif (type in ['plasma_desktopthemes', 'plasma5_desktopthemes']
        and self.install_plasmapkg(temp_path, 'theme')):
            print('The plasma desktop theme has been installed')
            os.remove(temp_path)
        elif (type == 'kwin_effects'
        and self.install_plasmapkg(temp_path, 'kwineffect')):
            print('The KWin effect has been installed')
            os.remove(temp_path)
        elif (type == 'kwin_scripts'
        and self.install_plasmapkg(temp_path, 'kwinscript')):
            print('The KWin script has been installed')
            os.remove(temp_path)
        elif (type == 'kwin_tabbox'
        and self.install_plasmapkg(temp_path, 'windowswitcher')):
            print('The KWin window switcher has been installed')
            os.remove(temp_path)
        elif self.uncompress_archive(temp_path, destination):
            print('The archive file has been uncompressed into ' + destination)
            os.remove(temp_path)
        else:
            print('Saving a file to ' + path)
            os.rename(temp_path, path)

        print('Done')

    def execute(self):
akiraohgaki's avatar
akiraohgaki committed
        if (self.meta['command'] in ['download', 'install']
        and self.meta['url']
        and self.meta['type'] in self.destinations
        and self.meta['filename']):
            if self.meta['command'] == 'download':
                self.download()
            elif self.meta['command'] == 'install':
                self.install()
        else:
            raise Exception('Incorrect XDG-URL ' + self.xdg_url)
akiraohgaki's avatar
akiraohgaki committed

'''
class XdgUrlApp(Tkinter.Frame):
    """Confirmation dialog for xdgurl"""

    def __init__(self, master=None, core=None):
        Tkinter.Frame.__init__(self, master)
        self.pack()
        self.core = core
        self.master.title('xdgurl')
        self.master.geometry('300x120')
        self.create_widget()

    def create_widget(self):
        execute_text = 'Download'
        if self.core.meta['command'] == 'install':
            execute_text = 'Install'

        info_label = Tkinter.Label(self, text=execute_text + ': ' + self.core.meta['filename'])
        info_label.pack(padx=10, pady=5, anchor=Tkinter.W)

        message_label = Tkinter.Label(self, text='Do you want to continue?')
        message_label.pack(padx=10, pady=5, anchor=Tkinter.W)

        execute_button = Tkinter.Button(self, text=execute_text, command=self.execute)
        execute_button.pack(padx=5, pady=10, side=Tkinter.RIGHT)

        quit_button = Tkinter.Button(self, text='Cancel', command=self.quit)
        quit_button.pack(padx=5, pady=10, side=Tkinter.RIGHT)

    def execute(self):
        self.core.execute()
        sys.exit()

    def quit(self):
        sys.exit()
'''

if __name__ == '__main__':
    if len(sys.argv) > 1:
        """
        window = Tkinter.Tk()
        core = XdgUrl(sys.argv[1])
        app = XdgUrlApp(window, core)
        app.mainloop()
        """

        core = XdgUrl(sys.argv[1])

        execute_text = 'Download'
        if core.meta['command'] == 'install':
            execute_text = 'Install'
        info_text = execute_text + ': ' + core.meta['filename'] + '\nFrom: ' + core.meta['url']

        window = Tkinter.Tk()
        window.withdraw()

        if tkMessageBox.askyesno('xdgurl', info_text + '\n\nDo you want to continue?'):
akiraohgaki's avatar
akiraohgaki committed
            try:
                core.execute();
            except Exception as e:
                message = ''
                if e.message:
                    message = e.message
                else:
                    message = str(e)
                tkMessageBox.showerror('xdgurl', info_text + '\n\n' + execute_text + ' failed\n' + message)
akiraohgaki's avatar
akiraohgaki committed
            else:
akiraohgaki's avatar
akiraohgaki committed
                tkMessageBox.showinfo('xdgurl', info_text + '\n\n' + execute_text + ' finished')
akiraohgaki's avatar
akiraohgaki committed
        sys.exit()
    else:
        print('xdgurl "XDG-URL"')
        sys.exit()