preface
At the risk of being locked up in a small black room wrote a nuggets automatic check-in lottery program contains automatic execution, check-in, free lottery, happy, email notification scripts, no longer need to forget to check in every day 😄
The thing is this New Year’s day because of playing too hi forgot the nuggets to sign so one and the same thing as a professional touch fish 🐟 player how can break the sign (well I was for the second day 5120 ore) decisive bought the sign card later in thinking why not write a daily automatic implementation of the sign script??
Have the ability to
-
action
It is executed at 9:00 every day - Email notification
- Cookie Expiration email notification
- Sign in
- With happy
- Lucky draw
- Set the number of days you want to redeem the surrounding automatically calculates how many more days you need to sign in
There are currently so many capabilities that the project will continue to maintain as new features are added (as long as they are not closed by the arc). If there are better projects, please mention them in the comments section
Start quickly
The #juejinCheckInFork
Go to your own warehouse and then put the projectclone
down
After opening a project with an editor, you need to modify several items of data with manual entries to your own
// Config file
module.exports = {
// This parameter needs to be entered manually
cookie: ' '.// Request an address
baseUrl: 'https://api.juejin.cn'./ / API address
api: {... },// Mailbox configuration
emailConfig: {
163 | qq / / email service
service: '163'.// Enter the email address manually
email: ' '.// Email authorization code Manually
pass: ' ',}}Copy the code
Cookie obtaining method
Cookies have an expiration date of about a month or they expire when you log out
Log in and enter the nuggets, F12 open the console, select Network and randomly click an interface, find the cookie in the request header, select the data and right click to copy the value
Email Settings
So if you’re using email 163 for example, email qq and the same thing if you’re using email 163 you just set the service field to 163 and then you fill in your own email and you’re successfully logged in and you’ll see that you’ve sent yourself an email that looks something like this
Obtain authorization code ⚠️ : log in to email 163 and open Settings
Enable the following Settings: When IMAP/SMTP service is enabled, a pop-up window will pop up to send SMS messages. After wechat scan code, you can send SMS messages. (If QQ mailbox is enabled, you need to manually verify sending SMS messages.)
I have already added it here, so just click on the new authorization and it will pop up the QR code to scan and send SMS
After the SMS is sent, click I have sent and you will get your authorization code (note that the authorization code is only shown once). Paste the authorization into the pass field in the configuration file
After filling in all the parameters correctly, you can run the command node index.js locally. You can receive mail and there is a log message in the mail. Congratulations!
The project push will be modified after confirmation. The project push has set automatic execution. The automatic check-in will be performed at 9:00 every day and an email will be sent for notification
Since the use of automatic check-in, my mother no longer has to worry that I forget to sign in. Switching is not a dream
The specific implementation
If you are only interested in scripting, you can turn left here to 🚪. If you are interested in the implementation, I will share with you the specific implementation ideas
After I had an idea, I began to dig the gold sign-in related interface one by one to open the interface point to see what data is given to each data is used to do what after a long debugging script sign-in ability is completed function is mainly composed of the following several interfaces
/ / sign in
checkIn: '/growth_api/v1/check_in'.// check the check-in
getCheckStatus: '/growth_api/v1/get_today_status'.// Query the number of check-in days
getCheckInDays: '/growth_api/v1/get_counts'.// Query the current ore
getCurrentPoint: '/growth_api/v1/get_cur_point'.// check the lottery
getlotteryStatus: '/growth_api/v1/lottery_config/get'./ / draw
draw: '/growth_api/v1/lottery/draw'.// Check whether you are happy today
getDipLuckyStatus: '/growth_api/v1/lottery_lucky/my_lucky'./ / happy
dipLucky: '/growth_api/v1/lottery_lucky/dip_lucky'
Copy the code
Now, it’s pretty easy to connect to the interface. Who knows how to connect to a request library and just do it? I’m using Axios
Configure the request to write to index.js and throw the cookie in the config file into the request header
BaseURL = config. baseURL // Set cookie axios.defaults.headers['cookie'] = config.cookie // Intercept accordingly axios.interceptors.response.use((response) => { const { data } = response if (data.err_msg === 'success' && data.err_no === 0) { return data } else { return Promise.reject(data.err_msg) } }, (error) => { return Promise.reject(error) })Copy the code
The next step is to request the interface directly
The following main code
/** * check to see if you have checked in ** today@return {Boolean} Have you checked in */
const getCheckStatus = async() = > {try {
const getCheckStatusRes = await axios({
url: config.api.getCheckStatus,
method: 'get'
})
return getCheckStatusRes.data
} catch (error) {
throw 'Failed to check in! 【${error}】 `}}/** * query current ore ** /
const getCurrentPoint = async() = > {try {
const getCurrentPointRes = await axios({ url: config.api.getCurrentPoint, method: 'get' })
console.log('Current total ore:${getCurrentPointRes.data}Several `)}catch (error) {
throw 'Failed to query ore!${error.err_msg}`}}/** * Check the number of free lucky draws **@return {Boolean} Whether there are free draw times */
const getlotteryStatus = async() = > {try {
const getlotteryStatusRes = await axios({ url: config.api.getlotteryStatus, method: 'get' })
return getlotteryStatusRes.data.free_count === 0
} catch (error) {
throw 'Query free draw failed! 【${error}】 `}}/** ** */
const dipLucky = async() = > {try {
const getDipLuckyStatusRes = await axios({ url: config.api.getDipLuckyStatus, method: 'post' })
const dipLuckyRes = await axios({ url: config.api.dipLucky, method: 'post' })
console.log('With beaming success! 🎉 [Current lucky value:${dipLuckyRes.data.total_value}/ 6000 】 `)}catch (error) {
throw 'With beaming failure!${error}`}}/** ** lucky draw ** /
const draw = async() = > {try {
const freeCount = await getlotteryStatus()
if (freeCount) {
// There are no free lucky draws
throw 'Use up today's free draw'
}
// Be happy first
await dipLucky()
// Start the lottery
const drawRes = await axios({ url: config.api.draw, method: 'post' })
console.log('Congratulations on your drawing [${drawRes.data.lottery_name}】 🎉 `)
if (drawRes.data.lottery_type === 1) {
// check the total ore
await getCurrentPoint()
}
} catch (error) {
console.error('Lottery failure! = = = = = = = > 【${error}】 `)}}/** * Query the check-in days **@return {Object} ContinuousDay Consecutive check-in days sumCount Total check-in days */
const getCheckInDays = async() = > {try {
const getCheckInDays = await axios({ url: config.api.getCheckInDays, method: 'get' })
return { continuousDay: getCheckInDays.data.cont_count, sumCount: getCheckInDays.data.sum_count }
} catch (error) {
throw 'Failed to query check-in days! 🙁 【${getCheckInDays.err_msg}】 `}}/** ** sign in ** /
const checkIn = async() = > {try {
// check whether you checked in today
const checkStatusRes = await getCheckStatus()
if(! checkStatusRes) {/ / sign in
const checkInRes = await axios({ url: config.api.checkIn, method: 'post' })
console.log('Check in successfully, current total ore${checkInRes.data.sum_point}`)
// Query the number of check-in days
const getCheckInDaysRes = await getCheckInDays()
console.log('Continuous raffle${getCheckInDaysRes.continuousDay}Days Total check-in days${getCheckInDaysRes.sumCount}`)
// Check in successfully to draw the lottery
await draw()
} else {
console.log('Signed in today at ✅')}}catch (error) {
console.error('Failed to sign in! = = = = = = = >${error}`)}}Copy the code
automated
About automatic execution I started to think of the scheme is through the server deployment to open a scheduled task to perform this way need to have a server is more trouble also some people with cloud function I am too lazy to go to the registration after finding a scheme is white whao Github Action through CI set scheduled task automatic execution every day Github has low requirements for everyone. Since I don’t know much about CI, I only learned a little about script this time. The specific code is as follows
name: jjCheckInScript
on:
schedule:
Minute hour Day Month Week = UTC +8
- cron: "0 1 * * *"
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
start:
Run the latest version of Ubuntu
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# installation node. Js
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14'
Install the dependency and execute the script
- name: npm install
run: npm install
- name: Start task
run: node index.js
Copy the code
The key code here is schedule, which changes the way the task is triggered to scheduled execution. The task will be automatically executed when the set time is reached. The task will run on the latest version of Ubuntu Minute hour Day month week (UTC Beijing time: **+8**)
Email 📧
The Nodemail library is used to send emails. It has very powerful functions and supports a variety of email services. It supports HTML content, plain text content, attachments, pictures and so on.
const nodemailer = require('nodemailer')
// Log processing renders script logs to HTML via EJS
const logs = []
console.oldLog = console.log
console.oldErr = console.error
console.log = (str) = > {
logs.push({
type: 'success'.text: str
})
console.oldLog(str)
}
console.error = (str) = > {
logs.push({
type: 'error'.text: str
})
console.oldErr(str)
}
/** ** Send email ** /
const sendEmail = async() = > {try {
const template = ejs.compile(fs.readFileSync(path.resolve(__dirname, 'email.ejs'), 'utf8'));
const transporter = nodemailer.createTransport({
service: process.env.SERVICE, // Email service
port: 465./ / port
secure: true.// Use TLS, SSL encryption port 465
secureConnection: true.auth: {
user: process.env.EMAIL, // Sender's mailbox
pass: process.env.PASS, // Email authorization code}})// Send an email
await transporter.sendMail({
from: process.env.EMAIL,
to: process.env.EMAIL,
subject: 'Nuggets sign up notice 🔔'.html: template({
logs: logs
})
})
} catch (error) {
console.error('Failed to send mail!${error}`)}}Copy the code
I wrote a simple log template in EJS to hold the script’s log. In the previous section, I overwrote console.log console.error to store STR in the logs array
Email sending is actually quite simple and you can see the official documentation for the configuration and here’s how it works
- service:Email service
Node mai l
There is already a lot of support internallyEmail serviceIf you fill in this field you don’t need to write ithost
- host:The host IP address of the mailbox is now on
IMAP/SMTP
The IP address of the mailbox is displayed - prot:The default port number is
465
- Secure: Configures secure links
- secureConnection:use
SSL
(Default false) - Auth. user: indicates the sender email address
- Auth. pass: indicates the email authorization code
- From: sender email address
- To: indicates the recipient email address
- Subject: indicates the email subject
- html:Email content
html
string
Actions Secrets Password security
As for the cookie email authorization code, it was written in a configuration folder at the beginning. Later, I proposed a better way is to use Actions secrets, which can avoid exposing key data (in case that boring guy takes your cookie to navigate 😏) or be careful
${{secrets.youkey}} ${{secrets.youkey}} ${{secrets.youkey}} ${{secrets.youkey Take this project for example
# Environment variablesenv:
COOKIE: ${{ secrets.COOKIE }}
PASS: ${{ secrets.PASS }}
EMAIL: ${{ secrets.EMAIL }}
SERVICE: ${{ secrets.SERVICE }}
Copy the code
And once we’ve done that we can use that data in our environment variables like this
process.env.COOKIE
process.env.EMAIL
Copy the code
However, the retrieved data cannot be displayed in Actions. In the output log, all passwords you defined are cleared and replaced with asterisks before the output log to prevent leakage
If you don’t think that’s secure enough and you can use data freely in your code you can try to encrypt your password
Q&A
Automatic execution delay
During the development test, Jobs found that he did not execute the 9:5 on time. When the company opened the Actions, he found that he did not execute the actions. At first, he thought it was the CRon time But that doesn’t affect our check-in function as long as we check in today
In my test, the corn time was set to 12:30 per day, but the actual execution time was 12:51, almost 20 minutes late
-cron: "30 4 * * *"Copy the code
The definition of Schedule in GitHub is as follows:
Note: The schedule event can be delayed during periods of high loads of GitHub Actions workflow runs. High load times include the start of every hour. To decrease the chance of delay, schedule your workflow to run at a different time of the hour.
Note: Scheduling events may be delayed during a high-load GitHub Action workflow run. High load times include the start of each hour. To reduce the chance of delay, schedule your workflow to run at different times of the hour.
In other words, the cron time in Schedule is not the actual execution time, but the queue time of workflow entering GitHub for execution. To simplify it, the queue time of workflow entering GitHub for execution depends on the load of GitHub workflow
This is not a fatal problem in check-in requirements. If you want to solve it, you can refer to the Github Action’s Schedule is not running on time
Why don’tdocument.cookie
?
The cookie obtained by the console input command is incomplete
This is what the console gotcookie
Compare the interfacecookie
There is a big difference
Eggs 🎉
In the debugging time found nuggets with happy interface bug!! But after I called the smudge interface, the interface was smudge successfully
Then I opened the lottery_lucky/ my_LUCKY interface and found the happiness value was +10
Then I click on the lucky draw page to be happy and successful!
The issue has been reported to the Nuggets team and is expected to be fixed soon (programmer: WTM ended again at the end of the year)
The statement 📢
This project is only suitable for learning and communication and does not have any other purposes. It has not gone through the excavation official team. If the title is blocked, it has nothing to do with me.
Other ideas or features are welcome to discuss at 👏