import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import requests
import time
import webbrowser
import datetime
from threading import Thread, Event

# 프로그램의 창 제목
Title = "치지직 단체 대기방"

# 실제로 방송이 켜져 있는지 확인하는 역할을 하는 Worker 클래스 정의
class Worker(Thread):
    def __init__(self, channel_ids, refresh, text_edit):
        super().__init__()
        self.channel_ids = channel_ids  # 입력받은 여러 개의 채널 ID 리스트
        self.refresh = refresh  # 갱신 간격(초)
        self.text_edit = text_edit  # 출력창(QTextEdit)에 로그를 출력하기 위한 객체
        self._stop_event = Event()  # 스레드를 멈추기 위한 이벤트 플래그

    def run(self):
        # 스레드를 실행하는 메인 로직
        while not self._stop_event.is_set():  # stop() 메서드가 호출되지 않은 동안 반복 실행
            for channel_id in self.channel_ids[:]:  # 채널 ID 리스트를 순회하며 방송 상태 확인
                try:
                    # 헤더 정보 정의 (웹사이트에 접근할 때 사용자 에이전트 정보 제공)
                    headers = {'User-Agent': 'Mozilla/5.0'}
                    # API를 통해 방송 정보 요청
                    request = requests.get(f"https://[Log in to view URL]", headers=headers)
                    
                    # API 요청이 실패한 경우 상태 코드 출력
                    if request.status_code != 200:
                        self.update_text(f"채널 {channel_id}에 대한 요청이 실패했습니다. 상태 코드: {request.status_code}")
                        continue

                    # 응답받은 JSON 데이터에서 방송 정보 추출
                    channel_info = request.json().get("content")

                    # 잘못된 채널 ID이거나 정보가 누락된 경우 처리
                    if channel_info is None or channel_info.get("channelId") is None:
                        self.update_text(f"{channel_id} - 존재하지 않는 채널 ID입니다.")
                        self.channel_ids.remove(channel_id)  # 잘못된 채널 ID는 리스트에서 제거
                        continue  # 다음 채널 확인

                    # 방송 상태 및 채널 이름 정보 추출
                    open_live = channel_info.get("openLive")  # 방송 켰는지 확인
                    channel_name = channel_info.get("channelName")  # 채널 이름 정보 가져오기

                    # 방송이 켜진 경우
                    if open_live:
                        self.update_text(f"{channel_name} 방송이 켜졌습니다! 10초 후에 접속합니다...")
                        # 10초 동안 카운트다운 후 웹브라우저로 방송 페이지 열기
                        for i in range(10, 0, -1):
                            if self._stop_event.is_set():  # 스레드 중지 요청이 있으면 종료
                                return
                            self.update_text(f"{i}초 남았습니다...")
                            time.sleep(1)
                        # 방송 URL을 웹브라우저에서 엽니다.
                        webbrowser.open(f"https://[Log in to view URL]", new=0)
                        self.channel_ids.remove(channel_id)  # 방송이 켜진 채널은 리스트에서 제거

                    # 방송이 켜지지 않은 경우 로그 기록
                    date = datetime.datetime.today().strftime('%H:%M:%S')
                    self.update_text(f'[{date}] {channel_name} 방송 대기중...')

                # 네트워크 요청에서 발생한 예외 처리
                except requests.exceptions.RequestException as e:
                    self.update_text(f"오류 발생: {e}")
                # 예상하지 못한 예외 처리
                except Exception as e:
                    self.update_text(f"예상치 못한 오류 발생: {e}")

            # 모든 채널 확인 후 설정한 시간만큼 대기 후 다시 확인
            self.update_text(f"모든 채널을 확인했습니다. {self.refresh}초 후에 다시 확인합니다...\n")
            time.sleep(self.refresh)

    # 스레드를 중지하는 메서드
    def stop(self):
        self._stop_event.set()

    # QTextEdit에 메시지를 안전하게 추가하는 메서드
    def update_text(self, message):
        QtCore.QMetaObject.invokeMethod(self.text_edit, "append", QtCore.Qt.QueuedConnection, QtCore.Q_ARG(str, message))

# UI를 구성하는 클래스 정의
class Ui_Form(object):
    def setupUi(self, Form):
        # 창 설정
        Form.setObjectName("Form")
        Form.resize(721, 321)
        
        # 시작 버튼
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(30, 20, 75, 23))
        self.pushButton.setObjectName("pushButton")
        
        # 로그 출력 창
        self.textEdit = QtWidgets.QTextEdit(Form)
        self.textEdit.setGeometry(QtCore.QRect(30, 150, 661, 171))
        self.textEdit.setObjectName("textEdit")
        
        # 정지 버튼
        self.pushButton_2 = QtWidgets.QPushButton(Form)
        self.pushButton_2.setGeometry(QtCore.QRect(620, 20, 75, 23))
        self.pushButton_2.setObjectName("pushButton_2")
        
        # 채널 ID 입력창
        self.lineEdit = QtWidgets.QLineEdit(Form)
        self.lineEdit.setGeometry(QtCore.QRect(30, 50, 661, 23))
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit.setPlaceholderText("채널 ID를 쉼표로 구분하여 입력하세요 (예: 1234, 5678)")  # 안내 문구 추가
        
        # 갱신 간격 입력창
        self.lineEdit_2 = QtWidgets.QLineEdit(Form)
        self.lineEdit_2.setGeometry(QtCore.QRect(30, 90, 661, 23))
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.lineEdit_2.setPlaceholderText("갱신 간격(초)를 입력하세요 (기본: 5초)")  # 안내 문구 추가

        # UI 요소와 텍스트 설정
        self.retranslateUi(Form)
        # 버튼과 함수 연결
        QtCore.QMetaObject.connectSlotsByName(Form)

        # 버튼을 클릭할 때 실행할 함수 연결
        self.pushButton.clicked.connect(self.start_checking)  # 시작 버튼 클릭 시 호출
        self.pushButton_2.clicked.connect(self.stop_program)  # 정지 버튼 클릭 시 호출

        # Worker 스레드 초기화
        self.worker = None

    # UI에 텍스트를 설정하는 함수
    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", Title))  # 창 제목 설정
        self.pushButton.setText(_translate("Form", "Start"))  # 시작 버튼 텍스트 설정
        self.pushButton_2.setText(_translate("Form", "Stop"))  # 정지 버튼 텍스트 설정

    # 방송 확인을 시작하는 함수
    def start_checking(self):
        if self.worker is None:  # Worker 스레드가 실행 중이 아닌 경우
            channel_ids = self.lineEdit.text().split(",")  # 쉼표로 구분된 채널 ID 입력값을 리스트로 변환
            channel_ids = [channel_id.strip() for channel_id in channel_ids]  # 공백 제거
            try:
                # 사용자가 입력한 갱신 간격이 숫자인지 확인
                refresh = int(self.lineEdit_2.text()) if self.lineEdit_2.text() else 5  # 입력값이 없으면 기본값 5초
            except ValueError:
                self.textEdit.append("유효하지 않은 갱신 간격 값입니다. 숫자를 입력하세요.")
                return

            # Worker 스레드를 생성하고 시작
            self.worker = Worker(channel_ids, refresh, self.textEdit)
            self.worker.start()  # 스레드 실행
        else:
            self.textEdit.append("이미 확인 중입니다.")  # 이미 실행 중인 경우 로그 메시지 출력

    # 프로그램을 정지하는 함수
    def stop_program(self):
        if self.worker is not None:
            self.worker.stop()  # Worker 스레드 정지
            self.worker.join()  # 스레드가 종료될 때까지 대기
            self.worker = None  # Worker 객체 초기화
            self.textEdit.append("프로그램이 정지되었습니다.")  # 정지 로그 출력

# 프로그램의 메인 실행 코드
if __name__ == "__main__":
    # PyQt5 애플리케이션을 실행하는 부분
    app = QtWidgets.QApplication(sys.argv)  # QApplication 객체 생성
    Form = QtWidgets.QWidget()  # QWidget으로 UI 창 생성
    ui = Ui_Form()
    ui.setupUi(Form)  # UI 설정
    Form.show()  # 창 표시
    sys.exit(app.exec_())  # 애플리케이션 종료
    


# Worker 클래스: 스레드로 채널의 방송 상태를 주기적으로 확인하는 기능을 수행.
# 
# run 메서드: 실제로 API 요청을 통해 방송 상태를 확인하고, 방송이 켜져 있으면 웹브라우저를 통해 해당 채널로 접속.
# stop 메서드: 스레드를 안전하게 중지하는 기능.
# update_text 메서드: 텍스트 출력 창에 메시지를 추가하는 함수.
# Ui_Form 클래스: 프로그램의 UI를 설정하고, 버튼을 통해 방송 확인을 시작하거나 정지할 수 있도록 연결.
# 
# start_checking 메서드: 채널 ID와 갱신 간격을 입력받아 방송 상태 확인을 시작.
# stop_program 메서드: 방송 상태 확인을 중지.
# 메인 실행 코드: PyQt5 애플리케이션을 시작하고 창을 띄우는 코드.

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: