Open-source project
shiyutim/tickets avatar
shiyutim/tickets

shiyutim/tickets: a Tauri and Rust workbench for Damai and Bilibili ticket purchases

大麦网(大麦)、bilibili(B站)会员购 演唱会调用接口的抢票软件,余票监控,微信通知。

3,381 stars433 forksRustMIT

At a glance

What is it?
A desktop app that schedules Damai H5 and Bilibili membership purchase orders, watches for returned stock, and pushes WeChat alerts. The README is unusually candid about its failure modes.
Who is it for?
Adopt it if you already hold valid Damai or Bilibili cookies, you are comfortable with a desktop app that must stay running, and you treat the stock monitor as a notification channel rather than a purchase guarantee. Do not adopt it if you need unattended operation across restarts, seat selection, or a tool that survives an interface change without a rebuild.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 18 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap between a ticket page and a ticket order

Buying a concert ticket on Damai or Bilibili membership purchase is a race against a countdown, and the browser gives you no help with the parts that matter. You have to be awake, logged in, on the right activity page, with the right session and ticket tier preselected, and you have to click at the right millisecond. shiyutim/tickets moves those steps into a Rust backend that owns the clock and the retry loop, and leaves the browser for the one thing it must do: paying on the official page.

The intended user is someone who already knows how to pull a Cookie out of browser developer tools. The README walks through it: log in on the official site, open the activity page, find the interface request in the Network panel, and copy the full Cookie from Request Headers. For Damai that Cookie must contain _m_h5_tk. For Bilibili it must contain SESSDATA and bili_jct. There is no OAuth flow and no login form inside the app. If that sentence does not describe you, this tool is not aimed at you.

Two platform workbenches, one Rust scheduler

The interface is a left-hand platform switcher over a Vue 3 front end, packaged by Tauri 1. Damai and Bilibili each get their own form and their own task list, and the README states that switching pages does not disturb a running task because waiting, retrying and cancelling live in the Rust backend.

The scheduling model has a hard constraint worth reading twice: each platform runs at most one purchase task at a time. Stock monitors are separate and can run many at once, with an application-wide ceiling of 100 tasks. A monitor does not consume a purchase slot.

Time handling is the most interesting mechanism in the repository. The correction value is defined as server time minus local time, so a correction of +150 ms means the machine is running slow. The backend waits for target sale time minus correction minus current local time. The front end countdown is display only. Once a task starts, it keeps the correction value captured at creation, so a later resync does not move its trigger. The app samples the public time endpoints at api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp and api.bilibili.com/x/report/click/now, prefers the Taobao one, picks the sample with the smallest round trip, and shows the estimated error. The README is explicit that the Bilibili endpoint is second-precision only and is not claimed to be millisecond accurate.

Installing from source and running a first monitor

There is no package manager install. The README points to the Releases page for per-system installers and warns that released packages may lag the current source. Building locally needs Node.js 18 or newer, a stable Rust 1.89 or newer, and the Tauri 1 system dependencies.

Clone the repository and install the JavaScript dependencies with the lockfile:

bash
npm ci

Then start the desktop app in development mode:

bash
npm run tauri dev

The repository ships a .cargo/config.toml that pins the official crates.io sparse source, and the README says this exists so that a global mirror missing dependencies such as subscription-proxy-pool does not break startup. You do not edit your global Cargo configuration. To produce an installer instead:

bash
npm run build
npm run tauri build

The README states the bundles land in src-tauri/target/release/bundle/. If you only want to look at the interface, npm run dev serves it in a browser, but the README is clear that the browser preview performs no platform requests, no database work and no purchase tasks.

For a first real use, open Settings and Help, then Accounts and Cookie, pick a platform, and paste a Cookie obtained as described above. Return to the platform workbench, choose the saved account, paste the official activity link and press load. The README gives this Damai example link:

bash
https://m.damai.cn/damai/detail/item.html?itemId=720545258599

Bilibili accepts show.bilibili.com/platform/detail.html?id=... and mall.bilibili.com/neul-next/ticket-renovation/detail.html?id=... . Then select the session, the ticket tier and the same number of attendees as tickets, and start the purchase or the reservation task.

Stock monitoring is a notification channel, not a purchase bot

The monitor tab is where the design choices get interesting. You add a monitor, pick a platform and account, load the activity, and choose a session and tier. Sold-out and not-yet-on-sale tiers can be selected, and no attendee or contact information is required. Query interval defaults to 60 seconds and accepts 5 to 3600 seconds. Maximum query count accepts 0 for unlimited. Start and end times are interpreted in Beijing time.

The README states plainly that the monitor only reads the detail interface and does not probe stock by attempting orders. It notifies only on an explicit in-stock or purchasable state. Missing fields, unknown states and tiers that have not been returned yet all mean keep waiting. A count of zero, not-yet-on-sale, suspended, sold out, and registration or waitlist states do not count as available. Failed queries retry after a delay, and five consecutive failures stop the monitor.

The honest part is the caveat: if the interface caches or does not expose stock, detection can be late, and by the time the notification arrives the ticket may be gone. The README defers to the official page as the final authority. On the first detection the monitor alerts, plays a sound if enabled, optionally sends WeChat, and then ends. It does not place an order for you. That separation is deliberate and it is the right call, but it means the tool shortens your reaction time rather than removing you from the loop.

WeChat alerts are bound in-app, with a plaintext caveat

Notifications do not require installing OpenClaw or configuring a model. In Settings and Help, under WeChat ClawBot notifications, you press scan to bind, scan the QR code with WeChat, and confirm. If the server asks for a verification code, you enter it on the page. After binding you send the bot one message, and the app identifies the receiving session and shows connected. A test notification button follows, and only then do you enable the purchase and stock alert switch. The switch and the binding save immediately, without the separate save button used elsewhere, and apply to both platforms.

The implementation follows Tencent's published WeChat plugin protocol, with the Rust backend doing the QR flow, session message collection and sending over HTTPS. The QR code is generated locally. Here is the trade-off the README does not soften: login credentials and session tokens are stored unencrypted in plaintext at wechat/binding.json in the application data directory, readable and writable only by the backend and never passed to the front end or the operation log. On Unix the directory is 0700 and the file is 0600. That is file permission hygiene, not encryption, and anyone with access to your user account can read the token.

Notifications are also not guaranteed. A purchase task sends one WeChat message after the platform confirms an order, containing platform, activity, session, tier and the official payment entry. The README stresses that this means an order was created and is awaiting payment, not that payment succeeded. If WeChat is unbound, the login expired, or sending fails, the purchase is unaffected: no order is changed and no re-order is triggered. A send timeout may have delivered anyway, so the app does not retry automatically. Long idle periods can break sending, and the README says to message the bot first to refresh the session. It also warns that long-term session validity and server-side push limits still need verification with a real WeChat account, and that a successful test notification does not prove unlimited proactive pushing.

Where the design breaks, and what to use instead

The most consequential limitation is stated in the README rather than discovered by surprise: quitting the app stops tasks, and a restart does not resume or automatically restore orders. There is no daemon, no service mode, no headless runner. The machine must stay awake, the network must stay up, and the process must stay alive. For a sale at 10:00 on a weekday, that means a running desktop session, not a server.

Other boundaries are equally concrete. Only tiers that do not require seat selection are supported. Payment happens on the official page. Expired logins or human verification must be handled on the official site first, then the activity reloaded and the task restarted. The README states that platform interfaces can change, that builds and simulated tests are not a substitute for a real account at a real sale time, and that purchase success is not guaranteed. The TODO list still carries other platform support and aggregated search, so neither exists yet.

A reasonable alternative is a general-purpose browser automation stack, for example Playwright driving a logged-in Chromium profile. The difference in approach is fundamental. Playwright reproduces the browser session and can click through seat selection and any page the site renders, which this project explicitly does not do. In exchange you own the timing problem yourself: you have to implement the clock offset, the retry policy, the stock polling and the alerting, and you inherit the fragility of a rendered page rather than a documented interface. shiyutim/tickets trades page-level coverage for a narrower, faster path through the platform's own H5 and detail interfaces.

Licence, data on disk and upgrade cost

The repository is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That is a statement about the licence text, not legal advice; if you plan to redistribute a modified build, read the LICENSE file in the repository root yourself.

The licence is permissive, but the README's own framing is not: it describes the project as intended for technical study and exchange, and asks that it not be used for commercial proxy buying. Those two statements sit in different registers, and a team deciding whether to ship this internally should read the second one as the author's stated intent rather than as a licence restriction.

Local data is split across two stores. Accounts live in tickets.accounts, with Cookies in plaintext on the device; purchase and monitor forms store only the account ID, not a copy of the credentials. General settings live in tickets.settings, and the README notes that old proxy and run-identifier fields from the SQLite SETTINGS table are migrated into fields that have not yet been saved, with the original table retained. Logging continues in the LOG and run-identifier LOG tables with parameter binding. Development and production use sql-test.db and sql.db respectively. Full attendee information is used only for the current run and is not written to logs or task history.

Upgrade cost is mostly a function of how fast the platforms move. The 0.5.0 to 0.6.0 gap spans roughly sixteen months and the changelog entry for that jump covers a rebuilt workbench, a new Bilibili membership purchase path including the createV2 chain, subscription proxy management and random User-Agent generation across interfaces, time sync, subscription downloads and update checks. In other words, a long quiet period was followed by a large refactor. Plan for the possibility that a platform interface change forces you to rebuild from source rather than wait for a release, since the README itself warns that published installers may not contain current functionality.

Editorial conclusion

Adopt it if you already hold valid Damai or Bilibili cookies, you are comfortable with a desktop app that must stay running, and you treat the stock monitor as a notification channel rather than a purchase guarantee. Do not adopt it if you need unattended operation across restarts, seat selection, or a tool that survives an interface change without a rebuild. Before trusting it, verify two things yourself: that your Damai cookie contains _m_h5_tk and your Bilibili cookie contains SESSDATA and bili_jct, and that the time correction value the app displays matches the offset you measure against api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp.

Frequently asked questions

Does shiyutim/tickets keep running after I close the app?

No. The README states that quitting the application stops tasks and that a restart does not automatically resume or restore orders. The computer must stay awake and the app must stay running for scheduled purchases, monitoring and WeChat notifications.

Which cookies does shiyutim/tickets need for Damai and Bilibili?

You copy the full Cookie from Request Headers on the official activity page. For Damai it must contain _m_h5_tk; for Bilibili it must contain SESSDATA and bili_jct. The README notes that saving an account only validates the format and does not prove the login is still valid.

Can shiyutim/tickets buy a seat-selected ticket or complete payment?

No. The README states that only tiers which do not require seat selection are currently supported, and that payment is completed on the official page. After an order is created you press the button to go to payment and confirm there.

Does the stock monitor place an order when a ticket appears?

No. The monitor only reads the detail interface, alerts on the first purchasable tier, and then ends. The README says it does not probe stock by attempting orders and does not place an order automatically, and that the ticket may already be sold out by the time the alert arrives.

Where does shiyutim/tickets store my account credentials?

Cookies are stored in plaintext in the unified account store tickets.accounts on the current device. WeChat login credentials and session tokens are stored unencrypted in wechat/binding.json in the application data directory, with 0700 directory and 0600 file permissions on Unix systems.

What do I need installed to build shiyutim/tickets from source?

The README requires Node.js 18 or newer, a stable Rust 1.89 or newer, and the Tauri 1 system dependencies. You install JavaScript dependencies with npm ci and start the desktop app with npm run tauri dev.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. shiyutim/tickets on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/shiyutim-tickets.svg)](https://hysenlabs.com/projects/shiyutim-tickets)