<gh_stars>0
import logging
from functools import wraps
from io import BytesIO
import subprocess
import json

import emoji
import zmq
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram import ParseMode
from telegram.ext import MessageFilter
from telegram.ext import CommandHandler, MessageHandler, CallbackQueryHandler
from telegram.ext import Updater, Filters

import config
from animation_helper.animation_functions import prepare_animation, prepare_video, load_photo

zmq_context = zmq.Context()


class FilterEmoji(MessageFilter):
    def filter(self, message):
        return message.text in emoji.UNICODE_EMOJI


#  Socket to talk to server
print("Connecting to tcp://127.0.0.1:2222")
socket = zmq_context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:2222")
print('Connected')


def restricted(func):
    @wraps(func)
    def wrapped(update, context, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in config.settings['user'] + config.settings['admin']:
            print("Unauthorized access denied for {}.".format(user_id))
            return
        return func(update, context, *args, **kwargs)

    return wrapped


def restricted_admin(func):
    @wraps(func)
    def wrapped(update, context, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in config.settings['admin']:
            print("Unauthorized access denied for {}.".format(user_id))
            return
        return func(update, context, *args, **kwargs)

    return wrapped


updater = Updater(token=config.settings['token'], use_context=True)

dispatcher = updater.dispatcher

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)


def download_to_buffer(file_id, context):
    raw_data = BytesIO()
    send_file = context.bot.get_file(file_id)
    send_file.download(out=raw_data)
    raw_data.seek(0)
    return raw_data


def send_animation_data(socket, np_array, fps=30, flags=0, copy=True, track=False):
    meta_data = dict(
        type='animation_data',
        dtype=str(np_array.dtype),
        shape=np_array.shape,
        fps=fps,
    )
    print(f'Sending animation data ({np_array.shape[0]} frames)')
    socket.send_json(meta_data, flags | zmq.SNDMORE)
    socket.send(np_array, flags, copy=copy, track=track)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_music(socket, name, flags=0):
    meta_data = dict(
        type='music',
        name=name
    )
    print(f'Sending music viz {name}')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_text(socket, text, flags=0):
    meta_data = dict(
        type='text',
        text=text
    )
    print(f'Sending text {text}')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_qr(socket, data, flags=0):
    meta_data = dict(
        type='qr',
        data=data
    )
    print(f'Sending QR code "{data}"')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_apple(socket, command, flags=0):
    meta_data = dict(
        type='apple',
        command=command
    )
    print(f'Apple Home Kit {command}"')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print(f"Received: {message}")


def send_opengl(socket, flags=0):
    meta_data = dict(
        type='opengl',
    )
    print(f'Sending openGL')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_clock(socket, clock_type, task=None, flags=0):
    mode = clock_type.partition('set_clock_')[2]
    if mode == 'stop':
        mode = 'stop_watch'
    meta_data = dict(
        type='clock',
        mode=mode,
        task=task,
    )
    print(f'Sending clock')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_cache_file(socket, file_path, file_type='video', flags=0):
    meta_data = dict(
        type='cache',
        file_type=file_type,
        cache=str(file_path.absolute()),
    )
    print(f'Sending {file_type} {file_path.absolute()}')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def start(update, context):
    context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
    print(update.effective_user.id)
    print(context)


def secret(update, context):
    if update.effective_user.id in config.settings['blacklist']:
        return None
    if not config.settings['admin']:
        if update.effective_user.id not in config.settings['admin']:
            config.settings['admin'].append(update.effective_user.id)
    else:
        if update.effective_user.id not in config.settings['user']:
            config.settings['user'].append(update.effective_user.id)
    config.settings_file.write_text(json.dumps(config.settings))
    context.bot.send_message(chat_id=update.effective_chat.id, text=f"User {update.effective_user.id} added")


@restricted
def qr(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"Preparing QR code ...")
    data = update['message']['text'].partition('/qr')[2].strip()
    send_qr(socket, data=data)
    reply_massage.edit_text(text=f"The QR code is now on display.")


@restricted
def apple_lamp(update, context):
    keyboard = [[InlineKeyboardButton("Setup", callback_data='set_apple_setup'),
                 InlineKeyboardButton("Start", callback_data='set_apple_start')]]
    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted_admin
def admin(update, context):

    keyboard = [[InlineKeyboardButton("Power off", callback_data='set_admin_off'),
                 InlineKeyboardButton("Restart", callback_data='set_admin_reboot')],
                [InlineKeyboardButton("Change secret", callback_data='set_admin_set_secret'),
                 InlineKeyboardButton("Status", callback_data='set_admin_status')],
                [InlineKeyboardButton("List users", callback_data='set_admin_list_user'),
                 InlineKeyboardButton("Remove user", callback_data='set_admin_delete_user')],
                [InlineKeyboardButton("Add admin", callback_data='set_admin_add'),
                 InlineKeyboardButton("Remove admin", callback_data='set_admin_remove')]
                ]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted_admin
def admin_callbacks(update, context, query):
    mode = query.data.partition('set_admin_')[2]
    print(mode)
    if mode == 'reboot':
        query.edit_message_text(text=f"Rebooting! See you in a second")
        subprocess.Popen(["sudo", "reboot"], stdin=None, stdout=None, stderr=None)

    elif mode == 'off':
        query.edit_message_text(text=f"Shutting down! 👋")
        subprocess.Popen(["sudo", "poweroff"], stdin=None, stdout=None, stderr=None)
    elif mode == 'status':
        cpu_temp_raw = subprocess.run(["/opt/vc/bin/vcgencmd", "measure_temp"], capture_output=True)
        cpu_temp = cpu_temp_raw.stdout.decode().partition('temp=')[2].partition("'")[0]
        disk_usage_raw = subprocess.run(["df", "/", "-h"], capture_output=True)
        disk_usage = disk_usage_raw.stdout.decode().split('\n')[1].partition('%')[0].rpartition(" ")[2]
        uptime_raw = subprocess.run(["uptime"], capture_output=True)
        uptime = uptime_raw.stdout.decode().partition('up ')[2].partition(",")[0].strip()
        query.edit_message_text(text=f"🌡 {cpu_temp} C\n\n💾 {disk_usage}%\n\n⏱ {uptime}")


@restricted
def clock(update, context):
    keyboard = [[InlineKeyboardButton("World", callback_data='set_clock_world'),
                 InlineKeyboardButton("Weather", callback_data='set_clock_weather')],
                [InlineKeyboardButton("Timer", callback_data='set_clock_timer'),
                 InlineKeyboardButton("Stopwatch", callback_data='set_clock_stop')]
                ]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted
def mod_stop_watch(update, context, query):
    task = query.data.partition('stop_watch_')[2]
    if not task:
        task = None
    send_clock(socket, 'set_clock_stop_watch', task)
    if task == 'done':
        query.edit_message_text(text="⏱ stopped")



@restricted
def stopwatch_key(update, context, query):
    keyboard = [[InlineKeyboardButton("Start", callback_data='set_stop_watch_start'),
                 InlineKeyboardButton("Stop", callback_data='set_stop_watch_stop')],
                [InlineKeyboardButton("Reset", callback_data='set_stop_watch_reset'),
                 InlineKeyboardButton("Done", callback_data='set_stop_watch_done')]
                ]

    reply_markup = InlineKeyboardMarkup(keyboard)
    query.edit_message_text('Please choose:', reply_markup=reply_markup)


@restricted
def animation(update, context):
    keyboard = [[InlineKeyboardButton("Rainfall", callback_data='set_animation_rainfall'),
                 InlineKeyboardButton("Firework", callback_data='set_animation_firework')],
                [InlineKeyboardButton("Soundtrace", callback_data='set_animation_music'),]]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted
def callback(update, context):
    query = update.callback_query

    # CallbackQueries need to be answered, even if no notification to the user is needed
    # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
    need_answer = True
    query.answer()
    if query.data == 'set_animation_music':
        send_music(socket, name='spectral')
    elif query.data == 'set_animation_firework':
        send_opengl(socket)
    elif 'stop_watch' in query.data:
        mod_stop_watch(update, context, query)
        need_answer = False
    elif query.data.startswith('set_clock_stop'):
        stopwatch_key(update, context, query)
        need_answer = False
    elif query.data.startswith('set_clock'):
        send_clock(socket, query.data)
    elif query.data.startswith('set_admin'):
        admin_callbacks(update, context, query)
        need_answer = False
    elif query.data == 'set_apple_setup':
        send_apple(socket, command='setup')
    elif query.data == 'set_apple_start':
        send_apple(socket, command='start')

    if need_answer:
        query.edit_message_text(text="Selected option: {}".format(query.data))


@restricted
def video(update, context):
    video_cache_file_raw = config.telegram_video_folder / f'new_raw.mp4'
    video_cache_file = config.telegram_video_folder / f'new.mp4'
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"A video! Start Downloading ({update.message.effective_attachment.file_size/1024:.1f} kB)...")
    raw_video_file = context.bot.get_file(update.message.effective_attachment.file_id)
    raw_video_file.download(video_cache_file_raw)
    prepare_video(video_cache_file_raw, video_cache_file)
    send_cache_file(socket, video_cache_file, file_type='video')
    reply_massage.edit_text(text=f"The video️ is now on display.")


@restricted
def sticker(update, context):

    sticker_cache_file = config.telegram_sticker_folder / f'{update.message.sticker.file_unique_id}.npz'

    if update.message.sticker.is_animated:
        reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                                 text=f"An animated {update.message.sticker.emoji} sticker!")
        if not sticker_cache_file.is_file():
            reply_massage.edit_text(text=f"This animated {update.message.sticker.emoji} sticker from *{update.message.sticker.set_name.replace('_', ' ').upper()}* is a new one. Let me work on it!", parse_mode=ParseMode.MARKDOWN)
            raw_sticker_file = context.bot.get_file(update.message.sticker.file_id)
            raw_sticker_file.download(sticker_cache_file.with_suffix('.tgs'))
            prepare_animation(sticker_cache_file.with_suffix('.tgs'))
        send_cache_file(socket, sticker_cache_file, file_type='sticker')

    else:
        reply_massage = context.bot.send_message(chat_id=update.effective_chat.id, text=f"A {update.message.sticker.emoji} sticker!")
        raw_sticker_data = download_to_buffer(update.message.sticker.file_id, context)
        send_animation_data(socket, load_photo(raw_sticker_data, box=True))

    reply_massage.edit_text(text=f"*{update.message.sticker.set_name.replace('_', ' ').upper()}* {update.message.sticker.emoji} sticker️ is now on display.", parse_mode=ParseMode.MARKDOWN)


@restricted
def photo(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"A photo! Start Downloading ({update.message.photo[0].file_size/1024:.1f} kB)...")

    raw_photo_data = download_to_buffer(update.message.photo[0].file_id, context)
    photo_data = load_photo(raw_photo_data, box=False)
    send_animation_data(socket, photo_data, fps=5)
    reply_massage.edit_text(text=f"The photo is now on display.")


@restricted
def text(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"A text! Rendering ...")
    send_text(socket, update.message.text)
    reply_massage.edit_text(text=f"The text is now on display.")


@restricted
def cb_emoji(update, context):
    emoji_value = update.message.text
    emoji_code = "_".join([f'{ord(c):x}' for c in emoji_value]).replace('_fe0f', '')
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"An emoji! (U+{emoji_code})")
    animated_emoji_file = config.telegram_sticker_folder / f'emoji_u{emoji_code}.npz'
    if animated_emoji_file.is_file():
        send_cache_file(socket, animated_emoji_file, file_type='sticker')
        reply_massage.edit_text(text=f"{emoji_value} (U+{emoji_code}) is now animated on display.")
    else:
        send_text(socket, emoji_value)
        reply_massage.edit_text(text=f"{emoji_value} (U+{emoji_code}) is now on display.")


@restricted
def catch_all(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"What is this?")
    pass


emoji_filter = FilterEmoji()
handler_list = [
    CommandHandler('start', start),
    CommandHandler(config.settings['secret'], secret),
    CommandHandler('animation', animation),
    CommandHandler('clock', clock),
    CommandHandler('apple', apple_lamp),
    CommandHandler('admin', admin),
    CommandHandler('qr', qr),
    MessageHandler(Filters.sticker, sticker),
    MessageHandler(Filters.document.gif | Filters.video, video),
    MessageHandler(Filters.photo, photo),
    MessageHandler(emoji_filter, cb_emoji),
    MessageHandler(Filters.text & (~Filters.command), text),
    MessageHandler(Filters.all, catch_all)
]
for handler in handler_list:
    dispatcher.add_handler(handler)

updater.dispatcher.add_handler(CallbackQueryHandler(callback))
print('Setup complete')
updater.start_polling()

import logging
from functools import wraps
from io import BytesIO
import subprocess
import json

import emoji
import zmq
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
from telegram import ParseMode
from telegram.ext import MessageFilter
from telegram.ext import CommandHandler, MessageHandler, CallbackQueryHandler
from telegram.ext import Updater, Filters

import config
from animation_helper.animation_functions import prepare_animation, prepare_video, load_photo

zmq_context = zmq.Context()


class FilterEmoji(MessageFilter):
    def filter(self, message):
        return message.text in emoji.UNICODE_EMOJI


#  Socket to talk to server
print("Connecting to tcp://127.0.0.1:2222")
socket = zmq_context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:2222")
print('Connected')


def restricted(func):
    @wraps(func)
    def wrapped(update, context, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in config.settings['user'] + config.settings['admin']:
            print("Unauthorized access denied for {}.".format(user_id))
            return
        return func(update, context, *args, **kwargs)

    return wrapped


def restricted_admin(func):
    @wraps(func)
    def wrapped(update, context, *args, **kwargs):
        user_id = update.effective_user.id
        if user_id not in config.settings['admin']:
            print("Unauthorized access denied for {}.".format(user_id))
            return
        return func(update, context, *args, **kwargs)

    return wrapped


updater = Updater(token=config.settings['token'], use_context=True)

dispatcher = updater.dispatcher

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    level=logging.INFO)


def download_to_buffer(file_id, context):
    raw_data = BytesIO()
    send_file = context.bot.get_file(file_id)
    send_file.download(out=raw_data)
    raw_data.seek(0)
    return raw_data


def send_animation_data(socket, np_array, fps=30, flags=0, copy=True, track=False):
    meta_data = dict(
        type='animation_data',
        dtype=str(np_array.dtype),
        shape=np_array.shape,
        fps=fps,
    )
    print(f'Sending animation data ({np_array.shape[0]} frames)')
    socket.send_json(meta_data, flags | zmq.SNDMORE)
    socket.send(np_array, flags, copy=copy, track=track)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_music(socket, name, flags=0):
    meta_data = dict(
        type='music',
        name=name
    )
    print(f'Sending music viz {name}')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_text(socket, text, flags=0):
    meta_data = dict(
        type='text',
        text=text
    )
    print(f'Sending text {text}')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_qr(socket, data, flags=0):
    meta_data = dict(
        type='qr',
        data=data
    )
    print(f'Sending QR code "{data}"')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_apple(socket, command, flags=0):
    meta_data = dict(
        type='apple',
        command=command
    )
    print(f'Apple Home Kit {command}"')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print(f"Received: {message}")


def send_opengl(socket, flags=0):
    meta_data = dict(
        type='opengl',
    )
    print(f'Sending openGL')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_clock(socket, clock_type, task=None, flags=0):
    mode = clock_type.partition('set_clock_')[2]
    if mode == 'stop':
        mode = 'stop_watch'
    meta_data = dict(
        type='clock',
        mode=mode,
        task=task,
    )
    print(f'Sending clock')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def send_cache_file(socket, file_path, file_type='video', flags=0):
    meta_data = dict(
        type='cache',
        file_type=file_type,
        cache=str(file_path.absolute()),
    )
    print(f'Sending {file_type} {file_path.absolute()}')
    socket.send_json(meta_data, flags)
    message = socket.recv_string()
    print("Received reply %s" % message)


def start(update, context):
    context.bot.send_message(chat_id=update.effective_chat.id, text="I'm a bot, please talk to me!")
    print(update.effective_user.id)
    print(context)


def secret(update, context):
    if update.effective_user.id in config.settings['blacklist']:
        return None
    if not config.settings['admin']:
        if update.effective_user.id not in config.settings['admin']:
            config.settings['admin'].append(update.effective_user.id)
    else:
        if update.effective_user.id not in config.settings['user']:
            config.settings['user'].append(update.effective_user.id)
    config.settings_file.write_text(json.dumps(config.settings))
    context.bot.send_message(chat_id=update.effective_chat.id, text=f"User {update.effective_user.id} added")


@restricted
def qr(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"Preparing QR code ...")
    data = update['message']['text'].partition('/qr')[2].strip()
    send_qr(socket, data=data)
    reply_massage.edit_text(text=f"The QR code is now on display.")


@restricted
def apple_lamp(update, context):
    keyboard = [[InlineKeyboardButton("Setup", callback_data='set_apple_setup'),
                 InlineKeyboardButton("Start", callback_data='set_apple_start')]]
    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted_admin
def admin(update, context):

    keyboard = [[InlineKeyboardButton("Power off", callback_data='set_admin_off'),
                 InlineKeyboardButton("Restart", callback_data='set_admin_reboot')],
                [InlineKeyboardButton("Change secret", callback_data='set_admin_set_secret'),
                 InlineKeyboardButton("Status", callback_data='set_admin_status')],
                [InlineKeyboardButton("List users", callback_data='set_admin_list_user'),
                 InlineKeyboardButton("Remove user", callback_data='set_admin_delete_user')],
                [InlineKeyboardButton("Add admin", callback_data='set_admin_add'),
                 InlineKeyboardButton("Remove admin", callback_data='set_admin_remove')]
                ]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted_admin
def admin_callbacks(update, context, query):
    mode = query.data.partition('set_admin_')[2]
    print(mode)
    if mode == 'reboot':
        query.edit_message_text(text=f"Rebooting! See you in a second")
        subprocess.Popen(["sudo", "reboot"], stdin=None, stdout=None, stderr=None)

    elif mode == 'off':
        query.edit_message_text(text=f"Shutting down! 👋")
        subprocess.Popen(["sudo", "poweroff"], stdin=None, stdout=None, stderr=None)
    elif mode == 'status':
        cpu_temp_raw = subprocess.run(["/opt/vc/bin/vcgencmd", "measure_temp"], capture_output=True)
        cpu_temp = cpu_temp_raw.stdout.decode().partition('temp=')[2].partition("'")[0]
        disk_usage_raw = subprocess.run(["df", "/", "-h"], capture_output=True)
        disk_usage = disk_usage_raw.stdout.decode().split('\n')[1].partition('%')[0].rpartition(" ")[2]
        uptime_raw = subprocess.run(["uptime"], capture_output=True)
        uptime = uptime_raw.stdout.decode().partition('up ')[2].partition(",")[0].strip()
        query.edit_message_text(text=f"🌡 {cpu_temp} C\n\n💾 {disk_usage}%\n\n⏱ {uptime}")


@restricted
def clock(update, context):
    keyboard = [[InlineKeyboardButton("World", callback_data='set_clock_world'),
                 InlineKeyboardButton("Weather", callback_data='set_clock_weather')],
                [InlineKeyboardButton("Timer", callback_data='set_clock_timer'),
                 InlineKeyboardButton("Stopwatch", callback_data='set_clock_stop')]
                ]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted
def mod_stop_watch(update, context, query):
    task = query.data.partition('stop_watch_')[2]
    if not task:
        task = None
    send_clock(socket, 'set_clock_stop_watch', task)
    if task == 'done':
        query.edit_message_text(text="⏱ stopped")



@restricted
def stopwatch_key(update, context, query):
    keyboard = [[InlineKeyboardButton("Start", callback_data='set_stop_watch_start'),
                 InlineKeyboardButton("Stop", callback_data='set_stop_watch_stop')],
                [InlineKeyboardButton("Reset", callback_data='set_stop_watch_reset'),
                 InlineKeyboardButton("Done", callback_data='set_stop_watch_done')]
                ]

    reply_markup = InlineKeyboardMarkup(keyboard)
    query.edit_message_text('Please choose:', reply_markup=reply_markup)


@restricted
def animation(update, context):
    keyboard = [[InlineKeyboardButton("Rainfall", callback_data='set_animation_rainfall'),
                 InlineKeyboardButton("Firework", callback_data='set_animation_firework')],
                [InlineKeyboardButton("Soundtrace", callback_data='set_animation_music'),]]

    reply_markup = InlineKeyboardMarkup(keyboard)

    update.message.reply_text('Please choose:', reply_markup=reply_markup)


@restricted
def callback(update, context):
    query = update.callback_query

    # CallbackQueries need to be answered, even if no notification to the user is needed
    # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery
    need_answer = True
    query.answer()
    if query.data == 'set_animation_music':
        send_music(socket, name='spectral')
    elif query.data == 'set_animation_firework':
        send_opengl(socket)
    elif 'stop_watch' in query.data:
        mod_stop_watch(update, context, query)
        need_answer = False
    elif query.data.startswith('set_clock_stop'):
        stopwatch_key(update, context, query)
        need_answer = False
    elif query.data.startswith('set_clock'):
        send_clock(socket, query.data)
    elif query.data.startswith('set_admin'):
        admin_callbacks(update, context, query)
        need_answer = False
    elif query.data == 'set_apple_setup':
        send_apple(socket, command='setup')
    elif query.data == 'set_apple_start':
        send_apple(socket, command='start')

    if need_answer:
        query.edit_message_text(text="Selected option: {}".format(query.data))


@restricted
def video(update, context):
    video_cache_file_raw = config.telegram_video_folder / f'new_raw.mp4'
    video_cache_file = config.telegram_video_folder / f'new.mp4'
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"A video! Start Downloading ({update.message.effective_attachment.file_size/1024:.1f} kB)...")
    raw_video_file = context.bot.get_file(update.message.effective_attachment.file_id)
    raw_video_file.download(video_cache_file_raw)
    prepare_video(video_cache_file_raw, video_cache_file)
    send_cache_file(socket, video_cache_file, file_type='video')
    reply_massage.edit_text(text=f"The video️ is now on display.")


@restricted
def sticker(update, context):

    sticker_cache_file = config.telegram_sticker_folder / f'{update.message.sticker.file_unique_id}.npz'

    if update.message.sticker.is_animated:
        reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                                 text=f"An animated {update.message.sticker.emoji} sticker!")
        if not sticker_cache_file.is_file():
            reply_massage.edit_text(text=f"This animated {update.message.sticker.emoji} sticker from *{update.message.sticker.set_name.replace('_', ' ').upper()}* is a new one. Let me work on it!", parse_mode=ParseMode.MARKDOWN)
            raw_sticker_file = context.bot.get_file(update.message.sticker.file_id)
            raw_sticker_file.download(sticker_cache_file.with_suffix('.tgs'))
            prepare_animation(sticker_cache_file.with_suffix('.tgs'))
        send_cache_file(socket, sticker_cache_file, file_type='sticker')

    else:
        reply_massage = context.bot.send_message(chat_id=update.effective_chat.id, text=f"A {update.message.sticker.emoji} sticker!")
        raw_sticker_data = download_to_buffer(update.message.sticker.file_id, context)
        send_animation_data(socket, load_photo(raw_sticker_data, box=True))

    reply_massage.edit_text(text=f"*{update.message.sticker.set_name.replace('_', ' ').upper()}* {update.message.sticker.emoji} sticker️ is now on display.", parse_mode=ParseMode.MARKDOWN)


@restricted
def photo(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"A photo! Start Downloading ({update.message.photo[0].file_size/1024:.1f} kB)...")

    raw_photo_data = download_to_buffer(update.message.photo[0].file_id, context)
    photo_data = load_photo(raw_photo_data, box=False)
    send_animation_data(socket, photo_data, fps=5)
    reply_massage.edit_text(text=f"The photo is now on display.")


@restricted
def text(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"A text! Rendering ...")
    send_text(socket, update.message.text)
    reply_massage.edit_text(text=f"The text is now on display.")


@restricted
def cb_emoji(update, context):
    emoji_value = update.message.text
    emoji_code = "_".join([f'{ord(c):x}' for c in emoji_value]).replace('_fe0f', '')
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"An emoji! (U+{emoji_code})")
    animated_emoji_file = config.telegram_sticker_folder / f'emoji_u{emoji_code}.npz'
    if animated_emoji_file.is_file():
        send_cache_file(socket, animated_emoji_file, file_type='sticker')
        reply_massage.edit_text(text=f"{emoji_value} (U+{emoji_code}) is now animated on display.")
    else:
        send_text(socket, emoji_value)
        reply_massage.edit_text(text=f"{emoji_value} (U+{emoji_code}) is now on display.")


@restricted
def catch_all(update, context):
    reply_massage = context.bot.send_message(chat_id=update.effective_chat.id,
                                             text=f"What is this?")
    pass


emoji_filter = FilterEmoji()
handler_list = [
    CommandHandler('start', start),
    CommandHandler(config.settings['secret'], secret),
    CommandHandler('animation', animation),
    CommandHandler('clock', clock),
    CommandHandler('apple', apple_lamp),
    CommandHandler('admin', admin),
    CommandHandler('qr', qr),
    MessageHandler(Filters.sticker, sticker),
    MessageHandler(Filters.document.gif | Filters.video, video),
    MessageHandler(Filters.photo, photo),
    MessageHandler(emoji_filter, cb_emoji),
    MessageHandler(Filters.text & (~Filters.command), text),
    MessageHandler(Filters.all, catch_all)
]
for handler in handler_list:
    dispatcher.add_handler(handler)

updater.dispatcher.add_handler(CallbackQueryHandler(callback))
print('Setup complete')
updater.start_polling()
#  Socket to talk to server # CallbackQueries need to be answered, even if no notification to the user is needed # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery