Genshin Impact daily check-in rewards

A script to collect Genshin Impact daily check-in rewards at startup and on an open tab at a random interval after reward reset. As long as you leave a tab with the page in the on startup and in the background, it will be collected.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Genshin Impact daily check-in rewards
// @namespace    Genshin Impact daily check-in rewards
// @version      1.9
// @description  A script to collect Genshin Impact daily check-in rewards at startup and on an open tab at a random interval after reward reset. As long as you leave a tab with the page in the on startup and in the background, it will be collected.
// @author       NoxPi
// @license      MIT
// @match        https://webstatic-sea.mihoyo.com/ys/event/signin-sea/*
// @match        https://act.hoyolab.com/ys/event/signin-sea-v3/*
// @grant        none
// @require  	 https://code.jquery.com/jquery-3.6.0.min.js#sha256=/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=
// @require      https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js#sha512=qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==

// ==/UserScript==

// Default settings
/* The time zone of when the daily rewards are refreshing */
const RESET_TIMEZONE = "+0800"; // UTC+8
/* A random second interval to make the request semi-random */
const MAX_RANDOM_SEC_SCEW = 900; // 15 minutes
/* For how long will the script will try to listen for changes this round, before waiting until next refresh interval */
const LOOK_TIME_SEC = 60; // 1 minute
/* Seconds of delay between near complete loading of the site and click */
const DELAY_CLICK_SEC = 10; // 10 seconds


// Reload the page after reward reset (Based on RESET_TIMEZONE) has passed, at random number of seconds (Based on MAX_RANDOM_SEC_SCEW).
var time_to_refresh = moment.duration(moment().utcOffset(RESET_TIMEZONE).add(1, 'day').startOf('day').diff(moment())).asMilliseconds();
setTimeout(function(){ location.reload(); }, time_to_refresh+Math.floor(Math.random() * (MAX_RANDOM_SEC_SCEW*1000)));


// On page load
$(window).on('load', function() {
    // Ensure that we have at least loaded to a certain point before proceeding
    // To be sure that the true active box is getting correctly marked
    console.log("GIDCR: Onload event triggered");

    // Options for mutationObserver
    let observer_options = {
        childList: true,
        subtree: true,
        attributes: true
    },
    // Look for elements that indicate that things are mostly loaded
    load_observer = new MutationObserver(look_for_loaded);
    load_observer.observe(document, observer_options);
    console.log("GIDCR: Starting observation")

    // Stop the MutationObserver from runnning after a set period of time
    // The refresh code below this section will refresh the page, re-running the script from the beginning.
    window.setTimeout(function(){
        console.log("GIDCR: Timeout reached. Disconnecting the observer")
        load_observer.disconnect();
    }, LOOK_TIME_SEC*1000);
});


// Callback looking for elements indicating loading (near) completion
function look_for_loaded(mutations, observer) {
    // Fetch all mutations on the whole list of rewards
    for (let mutation of mutations) {
        // Look for the the avatar icon class, which loads last and thus indicate succesful load of the contents.
        var pattern = /components\-home\-assets\-\_\_sign\-content\-test\_\-\-\-miss\-info\-\-\-/;
        if (pattern.test(mutation.target.className)) {
            // Last class have been mutated and is assumed to be loaded in
            console.log("GIDCR: Page loaded")

            // Look for an active rewards button and click it if it exist
            window.setTimeout(function(){
                // Get the "Reward history" button
                var reward = $('[class*="components-home-assets-__sign-content-test_---actived-day---"]');

                // Found an active reward button
                if (reward.length > 0) {
                    console.log("GIDCR: Clicking the reward button")

                    // Click it
                    setTimeout(function(){
                        reward.mouseover();
                        reward.click();
                    }, 2000);
                }
            }, DELAY_CLICK_SEC*1000);
        }
    }
}