본문 바로가기

Skills/Other Lang

Diablo4 월드보스 뜨는 시간을 확인하고 imessage 로 알람받자

요즘 디아4를 하고 있다.

크로스 플랫폼 지원도 되서 컴터는 물론 PS, Xbox 등 모든 기기에서 연속적으로 이어서 즐길 수 있다고 한다.

컴터가 없는 나로써는 PS4 에서 하고있는데 월드보스가 뜨는 시간을 맞춰 접속하거나 들어가기가 여간 징한게 아니였다.

Disablo 4 Life 라는 사이트에서 제공하는 월보 출현 알림기를 이용하고 있지만, 배틀넷 아이디를 연동하면

알람을 해준다고 하면서 어찌된 영문인지 알람이 안온다 이말이라...

배틀넷 API 에서 알람 횟수가 제한이 있는거 같아서.. 많은 유저가 이용하는 요즘 알람이 안먹는게 맞다고 추측해 보다가..

도저히 놓치고 싶지 않아서 Python 으로 'at' command (onetime 작업스케쥴러) 를 이용해서 보스의 리젠시간을 확인하고

10분 남으면 imessage 로 알람을 보내주는 코드를 만들어 보았다.

10분 전 메시지를 보내고, 또 리젠 10분 후 새로운 리젠정보를 갱신했다고 메시지를 보내준다.

스케쥴링도 코드 안에서 자동으로 해당 시간을 설정한다.

나의 플랫폼은 macOS ( Mac Air ) 이기 때문에 imessage 가 가장 손쉽게, 별다른 API 없이 무료로 메시지 기능을 구현할 수 있었다.

사전에 필요한 Python module 은 아래와 같이 설치해주면 된다. 이미 설치되어 있다면 이미 설치되어있다고 알려준다.

# pip install selenium datetime logging subprocess

Selenium 을 사용하기 위해서는 geckodriver 또는 chrome 웹드라이버가 필요하다.

Firefox 를 사용할 것이므로 geckodriver 를 아래 사이트에서 플랫폼에 맞게 다운로드 한다 :

 

Releases · mozilla/geckodriver

WebDriver for Firefox. Contribute to mozilla/geckodriver development by creating an account on GitHub.

github.com

코드는 아래와 같고, recipient 부분에 본인 전화번호를 넣어주면 된다.

#!/opt/homebrew/bin/python3.10
#
#    Diablo IV World Boss Notificator ( for Diablo4.life )
#                                           made by Mirr
# License: Free
#############################################################

from selenium import webdriver
from selenium.webdriver.firefox.options import Options
from datetime import datetime, timedelta
import subprocess,logging, time

logger = logging.getLogger()
logger.setLevel(logging.INFO)
    
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)
logger.addHandler(stream_handler)

# log를 파일에 출력
file_handler = logging.FileHandler('Diablo_alert.log')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)

def send_imessage(recipient, message):
    # Applescript for imessage sending
    script = f'tell application "Messages" to send "{message}" to buddy "{recipient}"'
    subprocess.call(['osascript', '-e', script])

def schedule_with_at(schedule_time):
    command = "/opt/homebrew/bin/python3.10 Diablo4_alert.py"  # Replace with your desired command
    Attime = schedule_time # Replace with your desired time in HH:MM format
    
    result = subprocess.run(f'atq | grep "{Attime}" | cut -f2', shell=True, capture_output=True, text=True)
    try:
        if result.stdout != "":
            logger.info(f"Already scheduled, Skipped")
        else:
            result = subprocess.run(f'echo "{command}" | at {Attime}', shell=True, capture_output=True, text=True, check=True)
            logger.info(result.stderr)
    except subprocess.CalledProcessError as e:
        logger.error(f"Error executing 'at' command: {e}")
        return False

# Define the recipient's phone number or email address
recipient = '+821012341234'  # Replace with the recipient's phone number or email address

# Set up the web driver (make sure to specify the path to the driver)
options = Options()
options.add_argument('-headless')  # Run Firefox in headless mode (without a visible browser window)
executable_path = './geckodriver'   # Please download or put geckodriver in same directory

try:
    # Load the webpage
    driver = webdriver.Firefox(options=options)
    url = 'https://diablo4.life/trackers/overview'
    driver.get(url)
    
    # Wait for the page to load and any dynamic content to be generated
    # You may need to adjust the sleep duration based on the page's loading time
    time.sleep(3)  # Wait for 3 seconds (adjust as needed)
except Exception as e:
    logger.error(f"Driver and Page Load Failed: {e}")

try:
    # Extract the desired content
    Boss = driver.find_element('class name', 'EventCountdown_title__MMm_B').text
    TimeElement = driver.find_element('class name', 'EventCountdown_countdown__sl85X').text.splitlines()
except Exception as e:
    logger.error(f"Element find failed: {e}")

# Quit the browser
driver.quit()

LeftTime = ''.join(TimeElement)

Hours = float(TimeElement[0])
Mins = float(TimeElement[2])
Secs = float(TimeElement[4])

# Get the text from the element
CurrentTime = datetime.now()
GenTime = timedelta(hours=Hours, minutes=Mins, seconds=Secs)
RealGTime = CurrentTime + GenTime

RunTime1 = RealGTime - timedelta(minutes=10)
RunTime2 = RealGTime + timedelta(minutes=10)

try:
    # Schedule
    schedule_with_at(RunTime1.strftime("%H:%M"))      # 10 Mins ago
    schedule_with_at(RunTime2.strftime("%H:%M"))      # Check new regen time
    logger.info(f'Added jobs +- 10 Minutes')
    
    message = f"{Boss} - left {LeftTime} Gen at " + RealGTime.strftime("%H:%M:%S")
    
    send_imessage(recipient, message)
    logger.info(message)
except Exception as e:
    logger.error(f"Error: {e}")

원래 뷰티풀솝을 이용해 가져오려고 해봤는데, 해당 사이트에서 제공하는 데이타가 javascript 로써,

'css selector' 나 'xpath' 등 요소 검사기등을 통해 텍스트형태로 긁어오기가 불가능하더라..

그래서 그냥 Selenium 으로 Firefox Web browser 를 headless 로 가동해서 데이타를 긁어오는 형태로 제작했다.

간단한 코드이므로 질문은 따로 받지 않겠다.

필요한 개선점이 있으면 자유롭게 수정해서 쓰면 된다.

(참고로 로깅부분은 테스트하면서 필요해서 넣었는데, Error 시 at 에서 메일을 시스템관리자에게 자동으로
보내주도록 되어 있어서 불필요한 사람은 빼도 된다.)

아래와 같이 메시지가 들어오면 끝이다.

atq 명령어로 스케쥴 확인, 로그도 한번 확인.

혹시 atrun 이 실행되지 않거나 에러가 발생한다면 아래 부분을 참고하자.

atrun 에 디스크접근 권한을 주는 부분이다.

 

Making "at" work on macOS

I am working on a CentOS server and schedule a task with command at # echo "touch a_long_file_name_file.txt" | at now + 1 minute job 2 at Wed Oct 31 13:52:00 2018 One minute later, # ls | grep

unix.stackexchange.com

*** 오늘도 밤샜다..... ㅠㅠ

'Skills > Other Lang' 카테고리의 다른 글

How to get Discord alarm for Diablo IV world Boss via python  (0) 2023.06.29
리눅스용 editplus 식 웹에디터...  (1) 2007.10.05
[PHP] @의 역할...  (0) 2005.11.29
[Perl]Perl 관련 사이트 모음  (0) 2005.10.30
루비사용자모임  (0) 2005.09.04