Skip to content

Instantly share code, notes, and snippets.

@S0nter
Created September 11, 2022 05:18
Show Gist options
  • Save S0nter/078b2236e7c42ae2447a1f77c45667a4 to your computer and use it in GitHub Desktop.
Save S0nter/078b2236e7c42ae2447a1f77c45667a4 to your computer and use it in GitHub Desktop.
Program, which can shutdown your computer
import sys
import csv
import os
import datetime
import winshell
import psutil
import ctypes
from ctypes import wintypes, windll
from win32com.client import Dispatch
from tkinter import messagebox
from PyQt6.QtWidgets import QApplication, QSystemTrayIcon, QWidget, QMenu, QLabel, QVBoxLayout, QSpinBox, QSizePolicy, \
QLayout, QGroupBox, QComboBox, QHBoxLayout
from PyQt6.QtGui import QPainter, QKeySequence, QIcon, QAction, QFont
from PyQt6.QtCore import QSize, Qt, QEvent, QTimer
# from PyQt6.Qt6 import *
sid = 0 # Время за компом (сек)
sid_sess = 0 # Время текущей сессии (сек)
it = 0 # Итерации
stat = []
one_sess = 0 # Длительность сессии (до выключения, минут)
eye_save_type = 0 # Тип выключения компа
eye_save_time = 1 # Длительность отдыха от монитора
eye_save_time_end = datetime.datetime.strptime(
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') # Конец отдыха от монитора
blocked = False
start = datetime.date.today()
now = datetime.date.today()
delta_t = start - now
load_iter = 0
sett = []
last_stat = []
class Timer(QWidget):
def __init__(self):
log('Timer __init__')
super().__init__()
self.setFixedSize(QSize(145, 110))
self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint)
self.setWindowTitle("Следилка")
self.setWindowIcon(QIcon('icon.ico'))
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
self.offset = None
self.installEventFilter(self)
self.time_show = QLabel(str(sid))
self.time_show.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.sett_w = Settings()
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.time_show)
self.tray_icon = QSystemTrayIcon(self)
self.tray_icon.setIcon(QIcon('icon.ico'))
self.tray_icon.activated.connect(self.restore_window)
t_stat = QAction("Статистика", self)
# t_stat.triggered.connect()
t_sett = QAction('Настройки', self)
t_sett.triggered.connect(self.sett_w.show)
t_show = QAction('Показать', self)
t_show.triggered.connect(self.show)
t_hide = QAction('Скрыть', self)
t_hide.triggered.connect(self.hide)
tray_menu = QMenu()
tray_menu.addAction(t_sett)
tray_menu.addAction(t_stat)
tray_menu.addSeparator()
tray_menu.addAction(t_show)
tray_menu.addAction(t_hide)
self.tray_icon.setContextMenu(tray_menu)
self.tray_icon.show()
self.runtime()
def closeEvent(self, event): # Запрет закрытия окна
event.ignore()
self.hide()
def paintEvent(self, ev): # Создание окна
# log('Paint event')
if sid > 36000:
self.setFixedSize(165, 120)
painter = QPainter(self)
painter.setRenderHint(QPainter.renderHints(painter).Antialiasing) # Убирание некрасивых краёв
painter.setBrush(Qt.GlobalColor.white)
painter.drawRoundedRect(self.rect(), 25, 25) # Закругление краёв
def eventFilter(self, source, event): # Перетаскивание окна
# log('eventFilter')
if event.type() == QEvent.Type.MouseButtonPress and event.button() == Qt.MouseButton.LeftButton:
self.offset = event.pos()
elif event.type() == QEvent.Type.MouseMove and self.offset is not None:
self.move(self.pos() - self.offset + event.pos())
return True
elif event.type() == QEvent.Type.MouseButtonRelease:
self.offset = None
return super().eventFilter(source, event)
def contextMenuEvent(self, e): # Контекстное меню
log('contextMenuEvent')
context = QMenu(self)
copy_act = context.addAction("Копировать")
copy_act.setShortcut(QKeySequence.StandardKey.Copy)
context.addSeparator()
stat_act = context.addAction("Статистика")
sett_act = context.addAction("Настройки")
context.addSeparator()
quit_act = context.addAction("Закрыть")
action = context.exec(self.mapToGlobal(e.pos()))
if action == copy_act:
log('ПКМ -> Копировать')
log(datetime.timedelta(seconds=sid))
elif action == stat_act:
log('ПКМ -> Статистика')
elif action == sett_act:
log('ПКМ -> Настройки')
self.sett_w.show()
elif action == quit_act:
log('ПКМ -> Quit')
datasave()
self.close()
# QApplication.instance().quit()
def restore_window(self, reason): # Возвращение окна из трея
if reason != QSystemTrayIcon.ActivationReason.Context:
if self.isHidden():
self.tray_icon.show()
self.showNormal()
else:
self.tray_icon.show()
self.hide()
def runtime(self):
log('runtime')
global sid
# self.setCentralWidget(self.time_show)
font = self.time_show.font()
font.setPointSize(30)
self.time_show.setFont(font)
self.time_show.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
QTimer.singleShot(0, self.runtimesec)
def runtimesec(self):
global sid, sid_sess, it, eye_save_time_end
# log('runtimesec')
self.time_show.setText(str(datetime.timedelta(seconds=sid)))
self.time_show.update()
sid += 1
sid_sess += 1
it += 1
if sid_sess == one_sess * 60 and one_sess > 0: # Если время сессии подошло к концу, то:
log('end os sess')
sid_sess = 0
eye_save_time_end = datetime.datetime.strptime(
datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') + \
datetime.timedelta(minutes=eye_save_time)
datasave()
eye_save()
else: # Иначе:
if it == 60: # Сейвы каждую минуту
datasave()
it = 0
if not blocked:
QTimer.singleShot(10, self.runtimesec)
else:
blc = Block()
blc.showNormal()
blc.blocksec()
# Block.blocksec(Block)
class Settings(QWidget):
def __init__(self):
global one_sess
log('Settings __init__')
super().__init__()
self.setWindowTitle("Настройки")
self.setWindowIcon(QIcon('icon.ico'))
self.setWindowFlags(Qt.WindowType.CustomizeWindowHint | Qt.WindowType.WindowCloseButtonHint)
self.s_one_sess_gr = QGroupBox('Отдых от монитора') # Отдых от монитора:
self.s_one_sess_gr.setCheckable(True)
self.s_eye_sess = QLabel('Длительность сеанса')
self.s_eye = QSpinBox()
self.s_eye.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
self.s_eye.setRange(1, 1440)
if one_sess > 0:
self.s_eye.setValue(one_sess)
else:
self.s_one_sess_gr.setChecked(False)
self.s_eye.setValue(1)
self.s_eye.setSuffix(' мин.')
self.s_eye_lay = QHBoxLayout()
self.s_eye_lay.setAlignment(Qt.AlignmentFlag.AlignLeft)
self.s_eye_lay.addWidget(self.s_eye_sess)
self.s_eye_lay.addWidget(self.s_eye)
self.s_eye_lay.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
self.s_eye_sess_end_label = QLabel('При окончании сеанса:')
self.s_eye_sess_end_list = QComboBox()
self.s_eye_sess_end_list.addItem('Выключить компьютер')
self.s_eye_sess_end_list.addItem('Гибернация')
self.s_eye_sess_end_list.addItem('Перезагрузка')
self.s_eye_sess_end_list.addItem('Заблокировать экран')
self.s_eye_sess_end_list.addItem('Экран блокировки')
if eye_save_type == 0: # Определение типа выкла
self.s_eye_sess_end_list.setCurrentText('Выключить компьютер')
elif eye_save_type == 1:
self.s_eye_sess_end_list.setCurrentText('Гибернация')
elif eye_save_type == 2:
self.s_eye_sess_end_list.setCurrentText('Перезагрузка')
elif eye_save_type == 3:
self.s_eye_sess_end_list.setCurrentText('Заблокировать экран')
elif eye_save_type == 4:
self.s_eye_sess_end_list.setCurrentText('Экран блокировки')
self.s_eye_sess_end_lay = QHBoxLayout()
self.s_eye_sess_end_lay.addWidget(self.s_eye_sess_end_label)
self.s_eye_sess_end_lay.addWidget(self.s_eye_sess_end_list)
self.s_eye_rest_label = QLabel('Требовать отдыха от монитора на')
self.s_eye_rest_spin = QSpinBox()
self.s_eye_rest_spin.setRange(1, 1440)
self.s_eye_rest_spin.setValue(eye_save_time)
self.s_eye_rest_spin.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
self.s_eye_rest_spin.setSuffix(' мин.')
self.s_eye_rest_lay = QHBoxLayout()
self.s_eye_rest_lay.setAlignment(Qt.AlignmentFlag.AlignLeft)
self.s_eye_rest_lay.addWidget(self.s_eye_rest_label)
self.s_eye_rest_lay.addWidget(self.s_eye_rest_spin)
self.s_one_sess_gr_lay = QVBoxLayout(self.s_one_sess_gr)
self.s_one_sess_gr_lay.addLayout(self.s_eye_lay)
self.s_one_sess_gr_lay.addLayout(self.s_eye_sess_end_lay)
self.s_one_sess_gr_lay.addLayout(self.s_eye_rest_lay)
# if one_sess > 0:
# self.s_one_sess_gr.setChecked(True)
# self.s_eye.setValue(one_sess)
# else:
# self.s_eye_sess.setDisabled(True)
# self.s_eye.setDisabled(True)
layout = QVBoxLayout()
layout.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
layout.addWidget(self.s_one_sess_gr)
self.setLayout(layout)
# def set_s_eye_type(self):
# if self.s_one_sess_ch.isChecked():
# self.s_eye_sess.setEnabled(True)
# self.s_eye.setEnabled(True)
# else:
# self.s_eye_sess.setEnabled(False)
# self.s_eye.setEnabled(False)
def closeEvent(self, event):
global one_sess, eye_save_type, eye_save_time
log(self.s_eye_sess_end_list.currentText())
if self.s_one_sess_gr.isChecked(): # Длительность сеанса
one_sess = self.s_eye.value()
if self.s_eye_sess_end_list.currentText() == 'Выключить компьютер': # Определение типа выкла
eye_save_type = 0
elif self.s_eye_sess_end_list.currentText() == 'Гибернация':
eye_save_type = 1
elif self.s_eye_sess_end_list.currentText() == 'Перезагрузка':
eye_save_type = 2
elif self.s_eye_sess_end_list.currentText() == 'Заблокировать экран':
eye_save_type = 3
eye_save_time = self.s_eye_rest_spin.value()
else:
self.s_eye.setValue(1)
one_sess = 0
datasave()
class Block(QWidget):
def __init__(self):
super().__init__()
# log('Block init')
# self.setStyleSheet("background: black;")
# self.setWindowOpacity(0.8)
# self.setWindowFlags(Qt.WindowType.WindowStaysOnTopHint)
# self.showFullScreen()
print('scrend')
layout = QVBoxLayout()
layout.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignCenter)
self.setLayout(layout)
print('layend')
label = QLabel()
label.setStyleSheet("color: red;")
label.setText("Отдых от монитора")
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
label.setFont(QFont("Arial", 40))
layout.addWidget(label)
print('labelend')
self.b_timer = QLabel()
self.b_timer.setStyleSheet("color: blue;")
self.b_timer.setText(f'До конца Х минут')
self.b_timer.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.b_timer.setFont(QFont("Arial", 40))
layout.addWidget(self.b_timer)
print('B_timer end')
QTimer.singleShot(0, self.blocksec)
def blocksec(self):
self.b_timer.setText(str(eye_save_time_end - datetime.datetime.now()))
QTimer.singleShot(1000, self.blocksec)
def sett_upd():
global sett
sett = [one_sess, eye_save_type, eye_save_time, str(eye_save_time_end)]
def last_stat_upd():
global last_stat
last_stat = [str(start), sid]
def dataload():
log('dataload')
global sid, stat, start, delta_t, now, one_sess, eye_save_type, eye_save_time
def readsett():
global one_sess, eye_save_type, eye_save_time, eye_save_time_end
with open('sett.slset', 'r', newline='') as f_s: # Загрузка настроек
s_reader = csv.reader(f_s)
for s_row in s_reader:
log(f'sett: {s_row}')
one_sess = int(s_row[0])
log(f'one_sess = {one_sess}')
eye_save_type = int(s_row[1])
eye_save_time = int(s_row[2])
eye_save_time_end = datetime.datetime.strptime(s_row[3], '%Y-%m-%d %H:%M:%S')
f_s.close()
def readstat():
global stat, start, sid
stat = []
last_stat_upd()
with open('stat.csv', 'r', newline='') as f: # Загрузка статистики
reader = csv.reader(f)
for row in reader:
start = datetime.datetime.strptime(row[0], '%Y-%m-%d').date()
sid = int(row[1])
stat.append(row)
f.close()
log('stat')
try:
readstat()
except FileNotFoundError:
log('except FileNotFoundError:')
make_file('stat')
except ValueError:
log('ValueError')
make_file('stat')
except IndexError:
log('IndexError')
make_file('stat')
readstat()
log(f'stat: {stat}')
log(f'sett: {sett}')
try:
readsett()
except FileNotFoundError:
log('except FileNotFoundError:')
make_file('s')
except ValueError:
log('ValueError')
make_file('s')
except IndexError:
log('IndexError')
make_file('s')
finally:
readsett()
log(f'sett loaded: {one_sess, eye_save_type, eye_save_time}')
log('dataload.end')
def make_file(type_f='stat'):
log('makefile')
if type_f == 'stat':
with open('stat.csv', 'w') as file:
writer = csv.writer(file, delimiter=',', lineterminator='\n')
writer.writerow(last_stat)
else:
sett_upd()
with open('sett.slset', 'w', newline='') as file:
writer = csv.writer(file, delimiter=',', lineterminator='\n')
writer.writerow(sett)
file.close()
def make_shortcut(name, target, path_to_save, w_dir='default', icon='default'):
log('make_shortcut')
if path_to_save == 'desktop':
'''Saving on desktop'''
# Соединяем пути, с учётом разных операционок.
path = os.path.join(winshell.desktop(), str(name) + '.lnk')
elif path_to_save == 'startup':
'''Adding to startup (windows)'''
user = os.path.expanduser('~')
path_to_save = os.path.join(r"%s/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/" % user,
str(name) + '.lnk')
else:
path_to_save = os.path.join(path_to_save, str(name) + '.lnk')
if icon == 'default':
icon = target
if w_dir == 'default':
w_dir = os.path.dirname(target)
# # С помощью метода Dispatch, обьявляем работу с Wscript
# # (работа с ярлыками, реестром и прочей системной информацией в windows)
shell = Dispatch('WScript.Shell')
# Создаём ярлык.
shortcut = shell.CreateShortCut(path_to_save)
# Путь к файлу, к которому делаем ярлык.
shortcut.Targetpath = target
# Путь к рабочей папке.
shortcut.WorkingDirectory = w_dir
# Тырим иконку.
shortcut.IconLocation = icon
# Обязательное действо, сохраняем ярлык.
shortcut.save()
def datasave():
log('datasave')
global sid, start, stat
save_file = open('statS.csv', 'a')
saver = csv.writer(save_file, delimiter=',', lineterminator='\n')
saver.writerows(stat)
saver.writerow(['\n'])
save_file.close()
save_file = open('settS.slset', 'a')
sett_saver = csv.writer(save_file, delimiter=',', lineterminator='\n')
sett_saver.writerow(sett)
sett_saver.writerow(['\n'])
save_file.close()
last_stat_upd()
if len(stat) > 0 and delta_t.days > 0: # Статистика
''' Если заход в прогу был не сегодня: '''
log('if len(stat) > 0 and delta_t.days > 0:')
log(f'{len(stat)} {delta_t.days}')
sid = 0
stat.append(last_stat)
else:
log('else: stat[-1] = last_stat')
log(f'len(stat) = {len(stat)}, delta_t.days = {delta_t.days}')
stat[-1] = last_stat
with open('stat.csv', 'w') as file:
writer = csv.writer(file, delimiter=',', lineterminator='\n')
if delta_t.days > 0:
if not len(stat) > 1:
'''Если сегодня старта проги не было и кол-во строк в документе не превышает одну:'''
log('if delta_t.days > 0 and not len(stat) > 1:')
writer.writerow(stat[-1])
writer.writerow(last_stat)
stat.append(last_stat)
else:
'''Если сегодня старта проги не было и кол-во строк в документе превышает одну:'''
log('elif delta_t.days > 0 and len(stat) > 1:')
writer.writerows(stat[:-1])
log(f'writer.writerows({stat[:-2]})')
writer.writerow(last_stat)
stat[-1] = last_stat
else:
if not len(stat) > 1:
'''Если сегодня старт проги был и кол-во строк в документе не превышает одну:'''
log('elif not (delta_t.days > 0) and not len(stat) > 1:')
writer.writerow(stat[-1])
stat[-1] = last_stat
else:
'''Если сегодня старт проги был и кол-во строк в документе превышает одну:'''
log('elif not (delta_t.days > 0) and len(stat) > 1:')
writer.writerows(stat[:-1])
writer.writerow(last_stat)
stat[-1] = last_stat
file.close()
log(f'stat: {stat}')
sett_upd()
with open('sett.slset', 'w') as file_s: # Настройки
writer = csv.writer(file_s, delimiter=',', lineterminator='\n')
writer.writerow(sett)
log(f'sett saved: {sett}')
log('datasave.end')
def thiswin():
pid = wintypes.DWORD()
active = ctypes.windll.user32.GetForegroundWindow()
active_window = ctypes.windll.user32.GetWindowThreadProcessId(active, ctypes.byref(pid))
pid = pid.value
for item in psutil.process_iter():
if pid == item.pid:
return item.name()
def pre_start():
global now, delta_t, start
log('pre_start')
print('pag', (eye_save_time_end - datetime.datetime.now()).seconds, eye_save_time_end)
if (eye_save_time_end - datetime.datetime.now()).total_seconds() > 0 and one_sess != 0:
eye_save()
now = datetime.date.today()
delta_t = now - start
if delta_t.days > 0:
log(f'if delta_t.days ({delta_t.days}) > 0: ')
messagebox.showinfo("Информация",
f"Время проведённое за компьютером в прошлый раз: {datetime.timedelta(seconds=sid)}")
start = datetime.date.today()
datasave()
now = datetime.date.today()
delta_t = now - start
make_shortcut(name='Sledilka', target=os.path.abspath('Sledilka.exe'), path_to_save='startup')
def eye_save():
global eye_save_time, eye_save_time_end, blocked
log('eye_save')
print(blocked)
# eye_save_time_end = datetime.datetime.now() + datetime.timedelta(minutes=eye_save_time)
print(eye_save_time_end, eye_save_time)
def hiber():
os.popen('shutdown -h')
def block():
global blocked
blocked = True
Block()
# print('blocksec')
# QTimer.singleShot(0, blk.blocksec)
def lock_scr():
global blocked
blocked = True
if eye_save_type == 0:
log('sutdown')
os.popen('shutdown -t 10 -s -c "Требуется отдых от монитора"')
elif eye_save_type == 1:
log('hiber')
QTimer.singleShot(5000, hiber)
messagebox.showinfo('Гибернация', 'Требуется отдых от монитора')
elif eye_save_type == 2:
log('restart')
os.popen('shutdown -t 10 -r -c "Требуется отдых от монитора"')
elif eye_save_type == 3:
log('block')
block()
elif eye_save_type == 4:
log('lock_scr')
lock_scr()
def log(text):
print(text)
log_wr = open('logs.txt', 'a')
log_wr.write(f'{text}\n')
def main():
global now
log('main')
dataload()
pre_start()
app = QApplication(sys.argv)
window = Timer()
window.show()
app.exec()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment