Initial commit
This commit is contained in:
commit
562c88aa8e
|
|
@ -0,0 +1,7 @@
|
|||
Lib/
|
||||
libs/
|
||||
Scripts/
|
||||
Include/
|
||||
build/
|
||||
*.cfg
|
||||
*.log
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 178 KiB |
|
|
@ -0,0 +1,566 @@
|
|||
import sys
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import json
|
||||
from datetime import datetime, time
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import pandas as pd
|
||||
from PySide6.QtWidgets import (
|
||||
QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QLineEdit,
|
||||
QComboBox, QSpinBox, QCheckBox, QProgressBar, QTextEdit, QFileDialog, QWidget, QMessageBox, QDialog, QTableWidget, QTableWidgetItem, QAbstractItemView, QDialogButtonBox
|
||||
)
|
||||
from PySide6.QtCore import Qt, QThread, Signal, QSettings
|
||||
|
||||
class BookmarkWorker(QThread):
|
||||
progress = Signal(int)
|
||||
log = Signal(str)
|
||||
completed = Signal() # 작업 완료 시 호출
|
||||
|
||||
def __init__(self, bookmarks, folder_name, bookmarks_path, chrome_path, remove_existing):
|
||||
super().__init__()
|
||||
self.bookmarks = bookmarks
|
||||
self.folder_name = folder_name
|
||||
self.bookmarks_path = bookmarks_path
|
||||
self.chrome_path = chrome_path
|
||||
self.remove_existing = remove_existing
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
# JSON 파일 읽기
|
||||
if not os.path.exists(self.bookmarks_path):
|
||||
self.log.emit(f"즐겨찾기 JSON 파일을 찾을 수 없습니다: {self.bookmarks_path}")
|
||||
return
|
||||
|
||||
try:
|
||||
with open(self.bookmarks_path, "r", encoding="utf-8") as file:
|
||||
file_content = file.read().strip()
|
||||
if not file_content: # 파일이 비어 있는 경우
|
||||
bookmarks_data = {"roots": {"bookmark_bar": {"children": []}}}
|
||||
self.log.emit("JSON 파일이 비어 있어 기본값으로 초기화합니다.")
|
||||
else:
|
||||
bookmarks_data = json.loads(file_content)
|
||||
except json.JSONDecodeError as e:
|
||||
self.log.emit(f"JSON 파일 파싱 중 오류 발생: {str(e)}")
|
||||
bookmarks_data = {"roots": {"bookmark_bar": {"children": []}}}
|
||||
self.log.emit("JSON 파일을 기본값으로 초기화합니다.")
|
||||
|
||||
# 기존 북마크 제거
|
||||
if self.remove_existing:
|
||||
bookmarks_data["roots"]["bookmark_bar"] = self.remove_existing_bookmarks(
|
||||
bookmarks_data["roots"]["bookmark_bar"]
|
||||
)
|
||||
|
||||
# 북마크 추가
|
||||
total_bookmarks = len(self.bookmarks)
|
||||
bookmark_bar = bookmarks_data["roots"]["bookmark_bar"]
|
||||
|
||||
# 상위 폴더 이름 생성
|
||||
current_time = datetime.now().strftime("%m-%d-%H-%M-%S") # 현재 날짜 및 시간 포맷
|
||||
parent_folder_name = f"거상북마크-{current_time}" # 상위 폴더 이름
|
||||
|
||||
# 상위 폴더 생성
|
||||
parent_folder = {
|
||||
"type": "folder",
|
||||
"name": parent_folder_name,
|
||||
"children": []
|
||||
}
|
||||
|
||||
# 하위 폴더 생성
|
||||
chunk_size = 100 # 하위 폴더에 넣을 북마크 수
|
||||
for idx, chunk_start in enumerate(range(0, total_bookmarks, chunk_size), start=1):
|
||||
# 하위 폴더 이름 생성
|
||||
folder_name = f"거상북마크-{self.folder_name}-{idx}" # 하위 폴더 이름 (예: 거상북마크-중국-1)
|
||||
|
||||
sub_folder = {
|
||||
"type": "folder",
|
||||
"name": folder_name,
|
||||
"children": []
|
||||
}
|
||||
|
||||
# 하위 폴더에 북마크 추가
|
||||
for bookmark in self.bookmarks[chunk_start:chunk_start + chunk_size]:
|
||||
sub_folder["children"].append({
|
||||
"type": "url",
|
||||
"name": bookmark['name'], # 몰 이름을 북마크 이름으로 설정
|
||||
"url": bookmark['url']
|
||||
})
|
||||
|
||||
# 상위 폴더에 하위 폴더 추가
|
||||
parent_folder["children"].append(sub_folder)
|
||||
|
||||
# 진행률 업데이트
|
||||
progress = int((chunk_start + len(self.bookmarks[chunk_start:chunk_start + chunk_size])) / total_bookmarks * 100)
|
||||
self.progress.emit(progress)
|
||||
|
||||
# 즐겨찾기 바에 상위 폴더 추가
|
||||
bookmark_bar["children"].append(parent_folder)
|
||||
|
||||
# 수정된 JSON 파일 저장
|
||||
with open(self.bookmarks_path, "w", encoding="utf-8") as file:
|
||||
json.dump(bookmarks_data, file, indent=4, ensure_ascii=False)
|
||||
|
||||
self.log.emit("즐겨찾기 추가 작업이 완료되었습니다!")
|
||||
|
||||
# 작업 완료 시 크롬 실행
|
||||
if os.path.exists(self.chrome_path):
|
||||
subprocess.Popen([self.chrome_path, "chrome://bookmarks/"])
|
||||
self.log.emit("크롬 북마크 관리 페이지를 열었습니다.")
|
||||
else:
|
||||
self.log.emit(f"크롬 실행 파일을 찾을 수 없습니다: {self.chrome_path}")
|
||||
|
||||
self.completed.emit()
|
||||
|
||||
except Exception as e:
|
||||
self.log.emit(f"오류 발생: {str(e)}", exc_info=True)
|
||||
self.progress.emit(0)
|
||||
|
||||
def remove_existing_bookmarks(self, node):
|
||||
"""
|
||||
북마크 데이터를 재귀적으로 탐색하여 '거상북마크'로 시작하는 모든 폴더를 제거합니다.
|
||||
:param node: 북마크 데이터의 현재 노드
|
||||
:return: 필터링된 북마크 데이터
|
||||
"""
|
||||
if not isinstance(node, dict):
|
||||
return node
|
||||
|
||||
# 폴더 이름이 '거상북마크'로 시작하면 제거
|
||||
if node.get("type") == "folder" and node.get("name", "").startswith("거상북마크"):
|
||||
self.log.emit(f"제거된 폴더: {node.get('name')}")
|
||||
return None
|
||||
|
||||
# 자식(children)이 있는 경우 재귀적으로 탐색
|
||||
if "children" in node:
|
||||
node["children"] = [
|
||||
self.remove_existing_bookmarks(child)
|
||||
for child in node["children"]
|
||||
if self.remove_existing_bookmarks(child) is not None
|
||||
]
|
||||
|
||||
return node
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(message)s")
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
# datetime을 문자열로 변환하는 어댑터 등록
|
||||
sqlite3.register_adapter(datetime, lambda dt: dt.strftime("%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
# 문자열을 datetime 객체로 변환하는 컨버터 등록
|
||||
sqlite3.register_converter("DATETIME", lambda s: datetime.strptime(s.decode("utf-8"), "%Y-%m-%d %H:%M:%S"))
|
||||
|
||||
# 고정된 비밀번호
|
||||
self.stored_password = "365"
|
||||
|
||||
# QSettings 초기화 (비밀번호 저장 및 불러오기용)
|
||||
self.settings = QSettings("WhenRideMycar", "BookmarkAdder")
|
||||
|
||||
# 비밀번호 확인 창 표시
|
||||
self.password = None
|
||||
self.show_password_dialog()
|
||||
|
||||
# 프로그램 실행 가능 여부 확인
|
||||
if self.password != self.stored_password:
|
||||
QMessageBox.critical(self, "비밀번호 오류", "비밀번호가 일치하지 않습니다. 프로그램을 종료합니다.")
|
||||
sys.exit()
|
||||
|
||||
self.setWindowTitle("크롬 즐겨찾기 추가 프로그램 (by 내차는언제타냐 feat.거상110+님)")
|
||||
self.setGeometry(300, 300, 800, 500)
|
||||
|
||||
# UI 구성
|
||||
self.layout = QVBoxLayout()
|
||||
self.buttons_layout = QHBoxLayout()
|
||||
self.filter_layout = QHBoxLayout()
|
||||
|
||||
# DB 입력 버튼
|
||||
self.db_input_button = QPushButton("DB 입력")
|
||||
self.db_input_button.setToolTip("엑셀 파일을 선택하여 DB에 저장합니다. 기존 DB를 제거하거나 추가로 데이터를 입력할 수 있습니다.")
|
||||
self.db_input_button.clicked.connect(self.load_excel)
|
||||
|
||||
# 기존 DB 제거 체크박스
|
||||
self.remove_db_checkbox = QCheckBox("기존 DB 제거")
|
||||
self.remove_db_checkbox.setToolTip("체크하면 기존 DB를 삭제하고 새롭게 데이터를 입력합니다.")
|
||||
|
||||
# 데이터 보기 버튼
|
||||
self.view_data_button = QPushButton("데이터 보기")
|
||||
self.view_data_button.setToolTip("DB 내용을 테이블 형식으로 표시하고 데이터를 수정할 수 있습니다.")
|
||||
self.view_data_button.setEnabled(False)
|
||||
self.view_data_button.clicked.connect(self.view_data)
|
||||
|
||||
# 드롭다운: 국가
|
||||
self.country_label = QLabel("국가")
|
||||
self.country_dropdown = QComboBox()
|
||||
self.country_dropdown.addItems(["미국", "유럽", "중국", "일본", "한국", "기타", "랜덤"])
|
||||
self.country_dropdown.setCurrentText("중국")
|
||||
|
||||
# 드롭다운: 등급
|
||||
self.grade_label = QLabel("등급")
|
||||
self.grade_dropdown = QComboBox()
|
||||
self.grade_dropdown.addItems(["일반", "파워", "빅파워", "랜덤"])
|
||||
self.grade_dropdown.setCurrentText("랜덤")
|
||||
|
||||
# 스핀박스: 갯수
|
||||
self.count_label = QLabel("갯수")
|
||||
self.count_spinbox = QSpinBox()
|
||||
self.count_spinbox.setMinimum(100)
|
||||
self.count_spinbox.setMaximum(1000)
|
||||
self.count_spinbox.setSingleStep(100)
|
||||
self.count_spinbox.setValue(100)
|
||||
|
||||
# 기존 북마크 제거 체크박스
|
||||
self.remove_existing_checkbox = QCheckBox("기존 북마크 제거")
|
||||
self.remove_existing_checkbox.setToolTip("체크하면 '거상북마크'로 시작하는 모든 북마크를 제거합니다.")
|
||||
|
||||
# 실행 버튼
|
||||
self.run_button = QPushButton("실행")
|
||||
self.run_button.setToolTip("선택된 필터 조건에 따라 DB에서 데이터를 가져와 북마크를 추가합니다.")
|
||||
self.run_button.clicked.connect(self.run_task)
|
||||
|
||||
# 로그 박스
|
||||
self.log_box = QTextEdit()
|
||||
self.log_box.setReadOnly(True)
|
||||
|
||||
# 프로그레스 바
|
||||
self.progress_bar = QProgressBar()
|
||||
|
||||
# 필터 레이아웃 구성
|
||||
self.filter_layout.addWidget(self.country_label)
|
||||
self.filter_layout.addWidget(self.country_dropdown)
|
||||
self.filter_layout.addWidget(QLabel(" "))
|
||||
self.filter_layout.addWidget(self.grade_label)
|
||||
self.filter_layout.addWidget(self.grade_dropdown)
|
||||
self.filter_layout.addWidget(QLabel(" "))
|
||||
self.filter_layout.addWidget(self.count_label)
|
||||
self.filter_layout.addWidget(self.count_spinbox)
|
||||
self.filter_layout.addWidget(QLabel(" "))
|
||||
self.filter_layout.addWidget(self.remove_existing_checkbox)
|
||||
|
||||
# 버튼 레이아웃 구성
|
||||
self.buttons_layout.addWidget(self.db_input_button)
|
||||
self.buttons_layout.addWidget(self.remove_db_checkbox)
|
||||
self.buttons_layout.addWidget(self.view_data_button)
|
||||
self.buttons_layout.addWidget(self.run_button)
|
||||
|
||||
# 메인 레이아웃 구성
|
||||
self.layout.addLayout(self.filter_layout)
|
||||
self.layout.addLayout(self.buttons_layout)
|
||||
self.layout.addWidget(self.log_box)
|
||||
self.layout.addWidget(self.progress_bar)
|
||||
|
||||
# 메인 위젯 설정
|
||||
self.main_widget = QWidget()
|
||||
self.main_widget.setLayout(self.layout)
|
||||
self.setCentralWidget(self.main_widget)
|
||||
|
||||
# 상태 변수
|
||||
self.db_path = "markets.db"
|
||||
|
||||
# DB 파일 확인
|
||||
self.check_db()
|
||||
|
||||
def show_password_dialog(self):
|
||||
"""비밀번호 입력 창을 표시"""
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("비밀번호 입력")
|
||||
dialog.setFixedSize(300, 150)
|
||||
|
||||
layout = QVBoxLayout(dialog)
|
||||
|
||||
# 비밀번호 입력 필드
|
||||
password_label = QLabel("비밀번호:")
|
||||
password_input = QLineEdit()
|
||||
password_input.setEchoMode(QLineEdit.Password)
|
||||
|
||||
# 저장된 비밀번호 불러오기
|
||||
saved_password = self.settings.value("password", "")
|
||||
if saved_password:
|
||||
password_input.setText(saved_password)
|
||||
|
||||
# 비밀번호 저장 체크박스
|
||||
save_password_checkbox = QCheckBox("비밀번호 저장")
|
||||
save_password_checkbox.setChecked(bool(saved_password)) # 저장된 비밀번호가 있으면 체크
|
||||
|
||||
# 확인 버튼
|
||||
button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, parent=dialog)
|
||||
button_box.accepted.connect(dialog.accept)
|
||||
button_box.rejected.connect(dialog.reject)
|
||||
|
||||
# 레이아웃 구성
|
||||
layout.addWidget(password_label)
|
||||
layout.addWidget(password_input)
|
||||
layout.addWidget(save_password_checkbox)
|
||||
layout.addWidget(button_box)
|
||||
|
||||
# 다이얼로그 실행
|
||||
if dialog.exec() == QDialog.Accepted:
|
||||
self.password = password_input.text()
|
||||
|
||||
# 비밀번호 저장 처리
|
||||
if save_password_checkbox.isChecked():
|
||||
self.settings.setValue("password", self.password)
|
||||
else:
|
||||
self.settings.remove("password")
|
||||
else:
|
||||
self.password = None
|
||||
|
||||
def log(self, message, exc_info=False):
|
||||
"""
|
||||
메시지를 로그에 출력하고, GUI 로그 박스에도 표시
|
||||
:param message: 출력할 메시지
|
||||
:param exc_info: True일 경우 traceback 정보 포함
|
||||
"""
|
||||
if exc_info:
|
||||
# traceback 정보 포함하여 로깅
|
||||
self.logger.error(message, exc_info=True)
|
||||
error_traceback = traceback.format_exc()
|
||||
self.log_box.append(f"{message}\n{error_traceback}")
|
||||
else:
|
||||
self.logger.info(message)
|
||||
self.log_box.append(message)
|
||||
|
||||
def check_db(self):
|
||||
if not os.path.exists(self.db_path):
|
||||
QMessageBox.warning(self, "DB 없음", "DB 파일이 없습니다. 엑셀을 지정하여 DB를 생성해주세요.")
|
||||
else:
|
||||
self.log("DB 파일이 로드되었습니다.")
|
||||
self.view_data_button.setEnabled(True)
|
||||
|
||||
def load_excel(self):
|
||||
file_path, _ = QFileDialog.getOpenFileName(self, "엑셀 파일 선택", "", "Excel Files (*.xlsx *.xls)")
|
||||
if not file_path:
|
||||
return
|
||||
|
||||
try:
|
||||
self.log("엑셀 파일을 불러오는 중...")
|
||||
|
||||
# 파일 확장자 확인
|
||||
ext = os.path.splitext(file_path)[-1].lower()
|
||||
|
||||
# 필수 열 이름 정의
|
||||
required_columns = ['country', 'mall_grade', 'mall_name', 'mall_url']
|
||||
|
||||
# 엑셀 파일 읽기
|
||||
if ext == ".xls":
|
||||
try:
|
||||
import xlrd
|
||||
df = pd.read_excel(file_path, sheet_name=0, engine="xlrd")
|
||||
except ImportError:
|
||||
self.log("xlrd 라이브러리가 필요합니다. 'pip install xlrd>=2.0.1' 명령으로 설치하세요.")
|
||||
return
|
||||
except xlrd.biffh.XLRDError as e:
|
||||
self.log(f"엑셀 파일을 열 수 없습니다. 파일 형식을 확인하세요: {e}")
|
||||
return
|
||||
elif ext == ".xlsx":
|
||||
try:
|
||||
df = pd.read_excel(file_path, sheet_name=0, engine="openpyxl")
|
||||
except Exception as e:
|
||||
self.log(f"엑셀 파일을 열 수 없습니다: {e}", exc_info=True)
|
||||
return
|
||||
else:
|
||||
self.log("지원되지 않는 파일 형식입니다. .xls 또는 .xlsx 파일을 선택하세요.")
|
||||
return
|
||||
|
||||
# 엑셀에서 가져온 열과 필수 열 비교
|
||||
available_columns = [col for col in required_columns if col in df.columns]
|
||||
if not available_columns:
|
||||
self.log("엑셀 파일에 필수 열이 없습니다. 필요한 열: " + ", ".join(required_columns))
|
||||
return
|
||||
|
||||
# 필요한 열만 가져오기
|
||||
df = df[available_columns]
|
||||
|
||||
# 누락된 열은 빈 값으로 추가
|
||||
for col in required_columns:
|
||||
if col not in df.columns:
|
||||
df[col] = "" # 누락된 열은 빈 값으로 채움
|
||||
|
||||
# 열 이름을 정렬하여 설정
|
||||
df = df[required_columns]
|
||||
|
||||
# datetime.time 타입 데이터를 문자열로 변환
|
||||
def convert_time_to_string(x):
|
||||
try:
|
||||
if isinstance(x, time): # 시간이면 변환
|
||||
return x.strftime("%H:%M:%S")
|
||||
return x # 아니면 그대로 반환
|
||||
except Exception as e:
|
||||
self.log(f"데이터 변환 중 에러 발생: {str(e)}")
|
||||
return x
|
||||
|
||||
if 'mall_name' in df.columns:
|
||||
df['mall_name'] = df['mall_name'].apply(convert_time_to_string)
|
||||
if 'mall_url' in df.columns:
|
||||
df['mall_url'] = df['mall_url'].apply(convert_time_to_string)
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
|
||||
if self.remove_db_checkbox.isChecked():
|
||||
# 기존 DB 제거 및 새 테이블 생성
|
||||
conn.execute("DROP TABLE IF EXISTS markets")
|
||||
conn.execute("""
|
||||
CREATE TABLE markets (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
country TEXT,
|
||||
mall_grade TEXT,
|
||||
mall_name TEXT,
|
||||
mall_url TEXT
|
||||
)
|
||||
""")
|
||||
self.log("기존 DB가 제거되었습니다. 새롭게 생성되었습니다.")
|
||||
|
||||
# 데이터 저장, 중복 방지
|
||||
df.drop_duplicates(subset=['country', 'mall_grade', 'mall_name', 'mall_url'], inplace=True)
|
||||
|
||||
# id 열을 자동 생성하지 않으므로, 기존 테이블 스키마를 유지하면서 데이터를 삽입
|
||||
for _, row in df.iterrows():
|
||||
conn.execute("""
|
||||
INSERT INTO markets (country, mall_grade, mall_name, mall_url)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""", (row['country'], row['mall_grade'], row['mall_name'], row['mall_url']))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
self.log("DB 저장 완료")
|
||||
except Exception as e:
|
||||
self.log(f"엑셀 파일을 불러오는 중 에러 발생: {str(e)}", exc_info=True)
|
||||
|
||||
def view_data(self):
|
||||
try:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
query = "SELECT * FROM markets"
|
||||
df = pd.read_sql_query(query, conn)
|
||||
conn.close()
|
||||
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("DB 데이터 보기")
|
||||
dialog.setGeometry(100, 100, 800, 400)
|
||||
|
||||
table = QTableWidget(dialog)
|
||||
table.setRowCount(len(df))
|
||||
table.setColumnCount(len(df.columns))
|
||||
table.setHorizontalHeaderLabels(df.columns)
|
||||
|
||||
for i, row in df.iterrows():
|
||||
for j, value in enumerate(row):
|
||||
item = QTableWidgetItem(str(value))
|
||||
if j == 0: # id 열 (편집 불가능)
|
||||
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
|
||||
table.setItem(i, j, item)
|
||||
|
||||
# 네 번째 열 너비 조정
|
||||
table.setColumnWidth(4, table.columnWidth(3) * 2)
|
||||
|
||||
# 테이블 정렬 활성화
|
||||
table.setSortingEnabled(True)
|
||||
|
||||
# 정렬을 위한 헤더 클릭 이벤트 연결
|
||||
table.horizontalHeader().sectionClicked.connect(lambda index: self.sort_table(table, index))
|
||||
|
||||
table.cellChanged.connect(lambda: self.confirm_edit(table))
|
||||
table.resize(780, 380)
|
||||
dialog.exec()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "오류", f"DB 데이터를 불러오는 중 오류 발생: {e}", exc_info=True)
|
||||
|
||||
|
||||
def sort_table(self, table, column_index):
|
||||
"""
|
||||
테이블 데이터를 정렬하는 함수
|
||||
:param table: QTableWidget
|
||||
:param column_index: 정렬할 열 인덱스
|
||||
"""
|
||||
try:
|
||||
order = table.horizontalHeader().sortIndicatorOrder() # 현재 정렬 방향 확인
|
||||
table.sortItems(column_index, order) # 해당 열에 따라 정렬
|
||||
self.log(f"{column_index + 1}번째 열을 정렬했습니다. 방향: {'오름차순' if order == Qt.AscendingOrder else '내림차순'}")
|
||||
except Exception as e:
|
||||
self.log(f"테이블 정렬 중 오류 발생: {str(e)}", exc_info=True)
|
||||
|
||||
def confirm_edit(self, table):
|
||||
reply = QMessageBox.question(self, "확인", "수정된 데이터를 저장하시겠습니까?", QMessageBox.Yes | QMessageBox.No)
|
||||
if reply == QMessageBox.Yes:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
for row in range(table.rowCount()):
|
||||
# id는 수정하지 않으므로 첫 번째 열은 그대로 사용
|
||||
record_id = table.item(row, 0).text()
|
||||
country = table.item(row, 1).text()
|
||||
mall_grade = table.item(row, 2).text()
|
||||
mall_name = table.item(row, 3).text()
|
||||
mall_url = table.item(row, 4).text()
|
||||
|
||||
# id를 기준으로 업데이트
|
||||
cursor.execute("""
|
||||
UPDATE markets
|
||||
SET country = ?, mall_grade = ?, mall_name = ?, mall_url = ?
|
||||
WHERE id = ?
|
||||
""", (country, mall_grade, mall_name, mall_url, record_id))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
self.log("수정된 데이터가 저장되었습니다.")
|
||||
else:
|
||||
self.log("수정이 취소되었습니다.")
|
||||
|
||||
def run_task(self):
|
||||
country = self.country_dropdown.currentText()
|
||||
grade = self.grade_dropdown.currentText()
|
||||
count = self.count_spinbox.value()
|
||||
remove_existing = self.remove_existing_checkbox.isChecked()
|
||||
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
query = "SELECT mall_name AS name, mall_url AS url FROM markets WHERE 1=1"
|
||||
|
||||
# 국가 필터
|
||||
if country != "랜덤":
|
||||
query += f" AND country = '{country}'"
|
||||
# 등급 필터
|
||||
if grade != "랜덤":
|
||||
query += f" AND mall_grade = '{grade}'"
|
||||
|
||||
# 랜덤 정렬 추가
|
||||
query += " ORDER BY RANDOM()"
|
||||
# 갯수 제한 추가
|
||||
query += f" LIMIT {count}"
|
||||
|
||||
try:
|
||||
df = pd.read_sql_query(query, conn)
|
||||
conn.close()
|
||||
|
||||
self.bookmarks = df.to_dict("records")
|
||||
self.log(f"{len(self.bookmarks)}개의 북마크를 추출했습니다.")
|
||||
except Exception as e:
|
||||
self.log(f"DB 쿼리 실행 중 오류 발생: {str(e)}", exc_info=True)
|
||||
conn.close()
|
||||
return
|
||||
|
||||
folder_name = f"거상북마크-{grade}"
|
||||
self.bookmarks_path = os.path.expanduser(r"~\AppData\Local\Google\Chrome\User Data\Default\Bookmarks")
|
||||
self.chrome_path = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
|
||||
|
||||
self.worker = BookmarkWorker(self.bookmarks, folder_name, self.bookmarks_path, self.chrome_path, remove_existing)
|
||||
self.worker.progress.connect(self.progress_bar.setValue)
|
||||
self.worker.log.connect(self.log)
|
||||
self.worker.completed.connect(self.task_completed)
|
||||
self.worker.start()
|
||||
|
||||
def task_completed(self):
|
||||
self.log("작업이 완료되었습니다!")
|
||||
QMessageBox.information(self, "완료", "즐겨찾기 추가 작업이 완료되었습니다.")
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
app = QApplication(sys.argv)
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
|
|
@ -0,0 +1,46 @@
|
|||
from cx_Freeze import setup, Executable
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 애플리케이션 이름과 버전
|
||||
application_name = "크롬 즐겨찾기 추가 프로그램"
|
||||
application_version = "1.0.0"
|
||||
|
||||
# 실행 파일 생성 설정
|
||||
base = None
|
||||
if sys.platform == "win32":
|
||||
base = "Win32GUI" # 콘솔 창 없이 실행하려면 'Win32GUI' 설정
|
||||
|
||||
# 애플리케이션 메인 파일 설정
|
||||
main_file = "main.py"
|
||||
|
||||
# 필요한 추가 파일 설정 (예: 리소스 파일, 아이콘 등)
|
||||
include_files = [
|
||||
("markets.db", "markets.db"), # 데이터베이스 파일 (필요 시)
|
||||
]
|
||||
|
||||
# 빌드 옵션
|
||||
build_options = {
|
||||
"packages": ["os", "sys", "sqlite3", "subprocess", "json", "pandas", "datetime", "PySide6"],
|
||||
"include_files": include_files,
|
||||
"excludes": [], # tkinter 미사용 시 제외
|
||||
}
|
||||
|
||||
# 실행 파일 설정
|
||||
executables = [
|
||||
Executable(
|
||||
script=main_file,
|
||||
base=base,
|
||||
target_name="BookmarkAdder.exe",
|
||||
icon="bookmaker.ico"
|
||||
)
|
||||
]
|
||||
|
||||
# setup() 함수 호출
|
||||
setup(
|
||||
name=application_name,
|
||||
version=application_version,
|
||||
description="크롬 즐겨찾기 추가 프로그램 (내차는언제타냐 feat.110+)",
|
||||
options={"build_exe": build_options},
|
||||
executables=executables,
|
||||
)
|
||||
Loading…
Reference in New Issue