Browse Source

Первая рабочая версия

dev
cofob 10 months ago
parent
commit
fe7aeddb4e
No known key found for this signature in database GPG Key ID: 9FFD2837DF98628F
  1. 4
      .gitignore
  2. 55
      addons/drp/livemode/__init__.py
  3. 45
      api.py
  4. 7
      configurator.py
  5. 45
      drp.py
  6. 34
      funcs.py
  7. 76
      main.py
  8. 34
      settings.py

4
.gitignore

@ -1,3 +1,7 @@
venv
config*
log.log
# ---> Python
# Byte-compiled / optimized / DLL files
__pycache__/

55
addons/drp/livemode/__init__.py

@ -1,11 +1,62 @@
from api import *
def get_active_window():
import sys
active_window_name = None
if sys.platform in ['linux', 'linux2']:
# Alternatives: http://unix.stackexchange.com/q/38867/4784
try:
import wnck
except ImportError:
logging.info("wnck not installed")
wnck = None
if wnck is not None:
screen = wnck.screen_get_default()
screen.force_update()
window = screen.get_active_window()
if window is not None:
pid = window.get_pid()
with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
active_window_name = f.read()
else:
try:
from gi.repository import Gtk, Wnck
gi = "Installed"
except ImportError:
logging.info("gi.repository not installed")
gi = None
if gi is not None:
Gtk.init([]) # necessary if not using a Gtk.main() loop
screen = Wnck.Screen.get_default()
screen.force_update() # recommended per Wnck documentation
active_window = screen.get_active_window()
pid = active_window.get_pid()
with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
active_window_name = f.read()
elif sys.platform in ['Windows', 'win32', 'cygwin']:
# http://stackoverflow.com/a/608814/562769
import win32gui
window = win32gui.GetForegroundWindow()
active_window_name = win32gui.GetWindowText(window)
elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
# http://stackoverflow.com/a/373310/562769
from AppKit import NSWorkspace
active_window_name = (NSWorkspace.sharedWorkspace()
.activeApplication()['NSApplicationName'])
else:
print("sys.platform={platform} is unknown. Please report."
.format(platform=sys.platform))
print(sys.version)
return active_window_name
class Addon(BaseDRPAddon):
class Meta(BaseDRPAddon.Meta):
name = 'Live Mode'
description = 'Аддон для отображения текущего активного окна в Windows'
version = '0.0.1'
app_name = 'livemode'
def __init__(self):
pass
def thread(self):
return {'details': get_active_window()}

45
api.py

@ -1,8 +1,32 @@
import logging
class BaseDRPAddon:
class Meta:
name = 'BaseDRPAddon'
description = 'BaseDRPAddon description'
version = '0.0.1'
app_name = 'basedrpaddon'
def thread(self):
return {'details': 'nothing'}
def proxy_thread(self):
r = self.thread()
self.log.debug('returned '+str(r))
return r
def __init__(self):
file_log = logging.FileHandler('log.log')
console_out = logging.StreamHandler()
logging.basicConfig(format='%(levelname)s:%(name)s -> %(message)s [%(asctime)s]',
level=logging.DEBUG,
handlers=(file_log, console_out))
self.log = logging.getLogger("addon.drp." + self.Meta.app_name)
self.setup()
def setup(self):
pass
class BaseStatusAddon:
@ -10,3 +34,24 @@ class BaseStatusAddon:
name = 'BaseStatusAddon'
description = 'BaseStatusAddon description'
version = '0.0.1'
app_name = 'basestatusaddon'
def thread(self):
return {'details': 'nothing'}
def proxy_thread(self):
r = self.thread()
self.log.debug('returned '+str(r))
return r
def __init__(self):
file_log = logging.FileHandler('log.log')
console_out = logging.StreamHandler()
logging.basicConfig(format='%(levelname)s:%(name)s -> %(message)s [%(asctime)s]',
level=logging.DEBUG,
handlers=(file_log, console_out))
self.log = logging.getLogger("addon.status."+self.Meta.app_name)
self.setup()
def setup(self):
pass

7
configurator.py

@ -0,0 +1,7 @@
import pickle
active_drp = input('ACTIVE DRP: ').strip()
# active_status = input('ACTIVE STATUS: ').strip()
active_status = None
app_id = int(input('APP ID: '))
with open('config', 'wb') as f:
pickle.dump({'addons': {'drp': active_drp, 'status': active_status}, 'app_id': app_id}, f)

45
drp.py

@ -0,0 +1,45 @@
import discord_rpc
from settings import *
import logging
file_log = logging.FileHandler('log.log')
console_out = logging.StreamHandler()
logging.basicConfig(format='%(levelname)s:%(name)s -> %(message)s [%(asctime)s]',
level=logging.DEBUG,
handlers=(file_log, console_out))
log = logging.getLogger("drp")
class DRP:
def __init__(self, app_id: (str, int)):
callbacks = {
'ready': self.ready_callback,
'disconnected': self.disconnected_callback,
'error': self.error_callback,
}
discord_rpc.initialize(app_id, callbacks=callbacks, log=False)
@staticmethod
def ready_callback(current_user):
global CURR_USER
CURR_USER = current_user
log.info('User -> {}'.format(current_user))
@staticmethod
def disconnected_callback(codeno, codemsg):
log.error('Disconnected from Discord rich presence RPC. Code {}: {}'.format(codeno, codemsg))
@staticmethod
def error_callback(errno, errmsg):
log.error('An error occurred! Error {}: {}'.format(errno, errmsg))
@staticmethod
def update(**kwargs):
discord_rpc.update_presence(**kwargs)
discord_rpc.update_connection()
discord_rpc.run_callbacks()
@staticmethod
def shutdown():
discord_rpc.shutdown()

34
funcs.py

@ -1,5 +1,8 @@
import os
import pickle
import importlib.util
from settings import *
import time
def check_module(module_name):
@ -45,3 +48,34 @@ def mkfile(*args):
if not os.path.isfile(path):
f = open(path, 'w')
f.close()
def save_cfg():
with open(get_path([BASE_FOLDER, 'config']), 'wb') as f:
pickle.dump(CONFIG, f)
pjoin = os.path.join
def drp_thread(DRP):
global DRP_CONFIG
while True:
time.sleep(DRP_UPDATE_TIME)
if not DRP_IS_RUNNING:
continue
DRP.update(**DRP_CONFIG)
DRP.shutdown()
def drp_addon_thread(func):
global DRP_CONFIG
while True:
time.sleep(DRP_UPDATE_TIME)
if not DRP_IS_RUNNING:
continue
DRP_CONFIG = func()
def get_user_avatar(user):
return f'https://cdn.discordapp.com/avatars/{user["id"]}/{user["avatar"]}.png?size=128'

76
main.py

@ -1,19 +1,52 @@
import importlib
import os
from funcs import *
import api
from settings import *
import threading
import drp
import os
import pickle
import shutil
import logging
file_log = logging.FileHandler('log.log')
console_out = logging.StreamHandler()
logging.basicConfig(format='%(levelname)s:%(name)s -> %(message)s [%(asctime)s]',
level=logging.DEBUG,
handlers=(file_log, console_out))
log = logging.getLogger("main")
# SETUP
# DRP INIT
DRP_THREAD = threading.Thread(target=drp_thread, args=(drp.DRP(DRP_DEFAULT_APP_ID), ))
DRP_THREAD.start()
# create dirs and files
mkdir('addons')
mkdir('addons', 'drp')
mkdir('addons', 'status')
mkdir(BASE_FOLDER, ADDONS_FOLDER)
if not os.path.isfile(get_path([BASE_FOLDER, 'config'])):
log.info('created config')
CONFIG = {}
with open(get_path([BASE_FOLDER, 'config']), 'wb') as f:
pickle.dump(CONFIG, f)
else:
try:
with open(get_path([BASE_FOLDER, 'config']), 'rb') as f:
CONFIG = pickle.load(f)
except:
log.error('cannot load config! created copy config.bak')
os.remove(get_path([BASE_FOLDER, 'config.bak']))
shutil.copy(get_path([BASE_FOLDER, 'config']), get_path([BASE_FOLDER, 'config.bak']))
CONFIG = {}
with open(get_path([BASE_FOLDER, 'config']), 'wb') as f:
pickle.dump(CONFIG, f)
mkdir(BASE_FOLDER, ADDONS_FOLDER, DRP_FOLDER)
mkdir(BASE_FOLDER, ADDONS_FOLDER, STATUS_FOLDER)
# drp addons import
drp_addon_modules = []
for name in os.listdir(os.path.join('addons', 'drp')):
if name in ['__pycache__']:
for name in os.listdir(os.path.join(ADDONS_FOLDER, DRP_FOLDER)):
if name in ADDONS_FILE_BLACKLIST:
continue
m = import_module('addons.drp.'+name)
m = import_module('.'.join([ADDONS_FOLDER, DRP_FOLDER, name]))
if m is not None:
drp_addon_modules.append(m)
drp_addons = []
@ -21,16 +54,19 @@ for addon in drp_addon_modules:
drp_addons.append(addon.Addon())
del drp_addon_modules
active_drp = None
for addon in drp_addons:
print(f'Loaded DRP Addon -> \n\tname -> {addon.Meta.name}\n\tdescription -> {addon.Meta.description}\n\t'
f'version -> {addon.Meta.version}\n')
if addon.Meta.app_name == CONFIG['addons']['drp']:
active_drp = addon
log.debug(f'Loaded DRP Addon -> \n\tname -> {addon.Meta.name}\n\tdescription -> {addon.Meta.description}\n\t'
f'version -> {addon.Meta.version}')
# status addons import
status_addon_modules = []
for name in os.listdir(os.path.join('addons', 'status')):
if name in ['__pycache__']:
for name in os.listdir(os.path.join(ADDONS_FOLDER, STATUS_FOLDER)):
if name in ADDONS_FILE_BLACKLIST:
continue
m = import_module('addons.status.'+name)
m = import_module('.'.join([ADDONS_FOLDER, STATUS_FOLDER, name]))
if m is not None:
status_addon_modules.append(m)
status_addons = []
@ -38,6 +74,14 @@ for addon in status_addon_modules:
status_addons.append(addon.Addon())
del status_addon_modules
active_status = None
for addon in status_addons:
print(f'Loaded Status Addon -> \n\tname -> {addon.Meta.name}\n\tdescription -> {addon.Meta.description}\n\t'
f'version -> {addon.Meta.version}\n')
if addon.Meta.app_name == CONFIG['addons']['status']:
active_status = addon
log.debug(f'Loaded Status Addon -> \n\tname -> {addon.Meta.name}\n\tdescription -> {addon.Meta.description}\n\t'
f'version -> {addon.Meta.version}')
log.debug('loaded addons')
DRP_ADDON_THREAD = threading.Thread(target=drp_addon_thread, args=(active_drp.proxy_thread, ))
DRP_ADDON_THREAD.start()

34
settings.py

@ -0,0 +1,34 @@
import time
import os
import inspect
import sys
def get_script_dir(follow_symlinks=True):
if getattr(sys, 'frozen', False):
path = os.path.abspath(sys.executable)
else:
path = inspect.getabsfile(get_script_dir)
if follow_symlinks:
path = os.path.realpath(path)
return os.path.dirname(path)
BASE_FOLDER = get_script_dir()
ADDONS_FOLDER = 'addons'
DRP_FOLDER = 'drp'
STATUS_FOLDER = 'status'
ADDONS_FILE_BLACKLIST = ['__pycache__']
DRP_IS_RUNNING = True
DRP_THREAD = None
DRP_ADDON_THREAD = None
STATUS_ADDON_THREAD = None
DRP_CONFIG = {
'details': 'Discord Rich Presence changer',
'large_image_key': 'drpc_avatar',
'start_timestamp': int(time.time())
}
DRP_UPDATE_TIME = 1
DRP_DEFAULT_APP_ID = 808725586230771752
CONFIG = {}
CURR_USER = {}