329 lines
14 KiB
Python
329 lines
14 KiB
Python
#!/usr/bin/python3
|
||
# -*- coding: utf-8 -*-
|
||
|
||
from PyQt5.QtCore import Qt
|
||
from PyQt5.QtWidgets import (
|
||
QMainWindow, QDialog, QListWidgetItem, QFileDialog, QMessageBox
|
||
)
|
||
from jsonIO import jsonIO
|
||
from form import Ui_MainWindow
|
||
from search import Ui_SearchDialog
|
||
|
||
|
||
statuses = {
|
||
"none": "",
|
||
"planned": "Запланировано",
|
||
"watching": "Смотрю",
|
||
"rewatching": "Пересматриваю",
|
||
"completed": "Просмотрено",
|
||
"on_hold": "Отложено",
|
||
"dropped": "Брошено"
|
||
}
|
||
|
||
|
||
class MainWindow(QMainWindow, Ui_MainWindow):
|
||
def __init__(self, parent=None):
|
||
QMainWindow.__init__(self, parent, flags=Qt.Window)
|
||
Ui_MainWindow.__init__(self)
|
||
self.ui = Ui_MainWindow()
|
||
self.ui.setupUi(self)
|
||
|
||
# self.file_list = jsonIO.load_json("JDM17_animes.json")
|
||
# for data in self.file_list:
|
||
# item = QListWidgetItem(data["target_title_ru"])
|
||
# item.setData(1, data["target_id"])
|
||
# self.ui.anime_list.addItem(item)
|
||
|
||
self.file_path = ""
|
||
self.file_list = []
|
||
|
||
for key, value in statuses.items():
|
||
self.ui.status.addItem(value, key)
|
||
|
||
self.ui.anime_list.currentItemChanged.connect(self.show_title_info)
|
||
self.ui.searchButton.clicked.connect(self.search_titles)
|
||
self.ui.actionOpenFile.triggered.connect(self.action_open_file)
|
||
self.ui.actionSaveFile.triggered.connect(self.action_save_file)
|
||
self.ui.actionCloseFile.triggered.connect(self.action_close_file)
|
||
self.ui.actionExit.triggered.connect(self.action_close_window)
|
||
self.ui.actionAddTitle.triggered.connect(self.action_add_title)
|
||
self.ui.actionRemoveTitle.triggered.connect(self.action_remove_title)
|
||
|
||
def show_question(self, title, text):
|
||
box = QMessageBox(QMessageBox.Question, title, text, parent=self)
|
||
box.addButton("Да", QMessageBox.YesRole) # 0
|
||
box.addButton("Нет", QMessageBox.NoRole) # 1
|
||
return box.exec() == 0
|
||
|
||
def find_title(self, target_id):
|
||
for data in self.file_list:
|
||
if data["target_id"] == target_id:
|
||
return data
|
||
return None
|
||
|
||
def check_changes(self, target_id):
|
||
tbl_to_check = {
|
||
"score": self.ui.score.value(),
|
||
"status": self.ui.status.itemData(self.ui.status.currentIndex()),
|
||
"episodes": self.ui.episodes.value(),
|
||
"rewatches": self.ui.rewatches.value(),
|
||
"text": self.ui.note.toPlainText()
|
||
}
|
||
title_data = self.find_title(target_id)
|
||
for key, value in tbl_to_check.items():
|
||
if title_data[key] != value:
|
||
return True
|
||
return False
|
||
|
||
def save_changes(self, target_id):
|
||
title_data = self.find_title(target_id)
|
||
title_data["score"] = self.ui.score.value()
|
||
status_code = self.ui.status.itemData(self.ui.status.currentIndex())
|
||
if status_code == "none":
|
||
QMessageBox.warning(self, "Предупреждение", "Выбран неверный статус, он не будет сохранен.")
|
||
else:
|
||
title_data["status"] = status_code
|
||
title_data["episodes"] = self.ui.episodes.value()
|
||
title_data["rewatches"] = self.ui.rewatches.value()
|
||
title_data["text"] = self.ui.note.toPlainText()
|
||
|
||
def clear_fields(self):
|
||
self.ui.target_title.clear()
|
||
self.ui.target_title_ru.clear()
|
||
self.ui.score.setValue(0)
|
||
self.ui.status.setCurrentIndex(self.ui.status.findData("none"))
|
||
self.ui.episodes.setValue(0)
|
||
self.ui.rewatches.setValue(0)
|
||
self.ui.note.clear()
|
||
|
||
def refill_anime_list(self):
|
||
self.ui.anime_list.clear()
|
||
for data in self.file_list:
|
||
if data["target_type"] != "Anime":
|
||
continue
|
||
if data["text"] is None:
|
||
data["text"] = ""
|
||
item = QListWidgetItem()
|
||
if data["target_title_ru"] != "":
|
||
item.setText(data["target_title_ru"])
|
||
else:
|
||
item.setText(data["target_title"])
|
||
item.setData(1, data["target_id"])
|
||
self.ui.anime_list.addItem(item)
|
||
|
||
def check_current_title(self, item, ask_save=True):
|
||
if item is None:
|
||
return
|
||
item_id = item.data(1)
|
||
if not self.check_changes(item_id):
|
||
return
|
||
if (ask_save and self.show_question("Подтверждение", "Сохранить изменения?")) or ask_save == False:
|
||
self.save_changes(item_id)
|
||
|
||
def show_title_info(self, current, previous):
|
||
if current is None:
|
||
return
|
||
self.check_current_title(previous)
|
||
self.clear_fields()
|
||
data = self.find_title(current.data(1))
|
||
self.ui.target_title.setText(data["target_title"])
|
||
self.ui.target_title_ru.setText(data["target_title_ru"])
|
||
self.ui.score.setValue(data["score"])
|
||
self.ui.status.setCurrentIndex(self.ui.status.findData(data["status"]))
|
||
self.ui.episodes.setValue(data["episodes"])
|
||
self.ui.rewatches.setValue(data["rewatches"])
|
||
self.ui.note.setText(data["text"])
|
||
|
||
def search_titles(self):
|
||
if self.file_path == "":
|
||
QMessageBox.critical(self, "Ошибка", "Сначала откройте список!")
|
||
return
|
||
text_to_search = self.ui.searchEdit.text().lower()
|
||
if len(text_to_search) == 0:
|
||
self.refill_anime_list()
|
||
return
|
||
self.check_current_title(self.ui.anime_list.currentItem())
|
||
self.ui.anime_list.clear()
|
||
for title in self.file_list:
|
||
if title["target_type"] != "Anime":
|
||
continue
|
||
if title["target_title_ru"].lower().find(text_to_search) != -1:
|
||
item = QListWidgetItem(title["target_title_ru"])
|
||
item.setData(1, title["target_id"])
|
||
self.ui.anime_list.addItem(item)
|
||
|
||
def action_open_file(self):
|
||
file_path, file_name = QFileDialog.getOpenFileName(parent=self,
|
||
caption=self.tr("Выберите ваш файл со списком"),
|
||
filter=self.tr("*.json"))
|
||
if file_path == "":
|
||
return
|
||
if jsonIO.is_valid_json(file_path):
|
||
self.file_path = file_path
|
||
self.file_list = jsonIO.load_json(file_path)
|
||
self.clear_fields()
|
||
self.refill_anime_list()
|
||
|
||
def action_save_file(self):
|
||
if self.file_path == "":
|
||
QMessageBox.critical(self, "Ошибка", "Сначала откройте список!")
|
||
return
|
||
self.check_current_title(self.ui.anime_list.currentItem())
|
||
if jsonIO.save_json(self.file_path, self.file_list):
|
||
QMessageBox.information(self, "Успешно", "Файл успешно сохранен.")
|
||
else:
|
||
QMessageBox.critical(self, "Ошибка", "Что-то пошло не так! Попробуйте еще раз.")
|
||
|
||
def action_close_file(self):
|
||
if self.file_path == "":
|
||
QMessageBox.critical(self, "Ошибка", "Сначала откройте список!")
|
||
return
|
||
if self.show_question("Вопрос", "Вы хотите сохранить файл?"):
|
||
self.check_current_title(self.ui.anime_list.currentItem(), ask_save=False)
|
||
self.action_save_file()
|
||
self.file_path = ""
|
||
self.file_list = []
|
||
self.ui.anime_list.clear()
|
||
self.clear_fields()
|
||
|
||
def action_close_window(self):
|
||
if self.show_question("Вопрос", "Вы хотите сохранить файл?"):
|
||
self.check_current_title(self.ui.anime_list.currentItem(), ask_save=False)
|
||
self.action_save_file()
|
||
self.close()
|
||
|
||
def action_add_title(self):
|
||
search_dialog = SearchDialog(self)
|
||
search_dialog.exec_()
|
||
|
||
def action_remove_title(self):
|
||
if self.file_path == "":
|
||
QMessageBox.critical(self, "Ошибка", "Сначала откройте список!")
|
||
return
|
||
selected_item = self.ui.anime_list.currentItem()
|
||
if selected_item is None:
|
||
QMessageBox.critical(self, "Ошибка", "Выберите тайтл из списка!")
|
||
return
|
||
target_id = selected_item.data(1)
|
||
title = self.find_title(target_id)
|
||
if title["target_title_ru"] != "":
|
||
title_name = title["target_title_ru"]
|
||
else:
|
||
title_name = title["target_title"]
|
||
if self.show_question("Подтверждение", "Вы действительно хотите удалить '{}'?".format(title_name)):
|
||
self.ui.anime_list.takeItem(self.ui.anime_list.currentRow())
|
||
for data in self.file_list:
|
||
if data["target_id"] == target_id:
|
||
self.file_list.remove(data)
|
||
QMessageBox.information(self, "Успешно", "Тайтл '{}' успешно удален из списка!".format(title_name))
|
||
|
||
def returnNewTitle(self, title_data):
|
||
# print(title_data)
|
||
# if self.find_title(title_data["target_id"]):
|
||
# QMessageBox.critical(self, "Ошибка", "Данный тайтл уже есть в списке!")
|
||
# return
|
||
pass
|
||
|
||
|
||
header = {
|
||
"User-Agent": "",
|
||
"Authorization": ""
|
||
}
|
||
|
||
|
||
from requests import post, get
|
||
from urllib.parse import urlencode
|
||
class SearchDialog(QDialog, Ui_SearchDialog):
|
||
def __init__(self, parent=None):
|
||
QDialog.__init__(self, parent, flags=Qt.Window)
|
||
Ui_SearchDialog.__init__(self)
|
||
self.ui = Ui_SearchDialog()
|
||
self.ui.setupUi(self)
|
||
|
||
self.parent = parent
|
||
|
||
# import tokens from tokens.json
|
||
if not jsonIO.is_valid_json("tokens.json"):
|
||
jsonIO.save_json("tokens.json", {
|
||
"useragent": "",
|
||
"client_id": "",
|
||
"client_secret": "",
|
||
"authorization_code": "",
|
||
"access_token": "",
|
||
"refresh_token": ""
|
||
})
|
||
QMessageBox.critical(self, "Ошибка", "Заполните 'tokens.json' своими данными чтобы поиск работал корректно!")
|
||
self.close()
|
||
else:
|
||
self.tokens = jsonIO.load_json("tokens.json")
|
||
for key, value in self.tokens.items():
|
||
if (key != "access_token" or key != "refresh_token") and value == "":
|
||
QMessageBox.critical(self, "Ошибка", "Заполните 'tokens.json' своими данными чтобы поиск работал корректно!")
|
||
self.close()
|
||
if self.tokens["access_token"] == "":
|
||
self.get_new_access_token()
|
||
self.update_headers()
|
||
|
||
self.ui.search.clicked.connect(self.search_titles)
|
||
|
||
def update_headers(self):
|
||
header["User-Agent"] = self.tokens["useragent"]
|
||
header["Authorization"] = "Bearer {}".format(self.tokens["access_token"])
|
||
|
||
def get_new_access_token(self):
|
||
response = post("https://shikimori.one/oauth/token", headers=header, data={
|
||
"grant_type": "authorization_code",
|
||
"client_id": self.tokens["client_id"],
|
||
"client_secret": self.tokens["client_secret"],
|
||
"code": self.tokens["authorization_code"],
|
||
})
|
||
if response.status_code == 200:
|
||
new_tokens = response.json()
|
||
self.tokens["access_token"] = new_tokens["access_token"]
|
||
self.tokens["refresh_token"] = new_tokens["refresh_token"]
|
||
jsonIO.save_json("tokens.json", self.tokens)
|
||
self.update_headers()
|
||
print("got new tokens")
|
||
|
||
def refresh_access_token(self):
|
||
response = post("https://shikimori.one/oauth/token", headers=header, data={
|
||
"grant_type": "refresh_token",
|
||
"client_id": self.tokens["client_id"],
|
||
"client_secret": self.tokens["client_secret"],
|
||
"refresh_token": self.tokens["refresh_token"],
|
||
})
|
||
if response.status_code == 200:
|
||
new_tokens = response.json()
|
||
self.tokens["access_token"] = new_tokens["access_token"]
|
||
self.tokens["refresh_token"] = new_tokens["refresh_token"]
|
||
jsonIO.save_json("tokens.json", self.tokens)
|
||
self.update_headers()
|
||
print("tokens updated", new_tokens)
|
||
|
||
def search_titles(self):
|
||
title_name = self.ui.to_search.text()
|
||
if len(title_name) == 0:
|
||
QMessageBox.critical(self, "Ошибка", "Введите название тайтла.")
|
||
return
|
||
response = get("https://shikimori.one/api/animes", headers=header, params={"search": title_name, "limit": 25})
|
||
# print(response.json())
|
||
if response.status_code == 401:
|
||
if response.json()["error"] == "invalid_token":
|
||
self.refresh_access_token()
|
||
# self.search_titles()
|
||
return
|
||
if response.status_code == 200:
|
||
found_titles = response.json()
|
||
if len(found_titles) == 0:
|
||
QMessageBox.information(self, "Информация", "Ничего не найдено. Попробуйте еще раз.")
|
||
return
|
||
self.ui.search_list.clear()
|
||
for data in found_titles:
|
||
item = QListWidgetItem()
|
||
if data["russian"] != "":
|
||
item.setText("{} | {}".format(data["russian"], data["name"]))
|
||
else:
|
||
item.setText(data["name"])
|
||
item.setData(1, data["id"])
|
||
self.ui.search_list.addItem(item)
|