Created
September 11, 2022 05:18
-
-
Save S0nter/078b2236e7c42ae2447a1f77c45667a4 to your computer and use it in GitHub Desktop.
Program, which can shutdown your computer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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