Skip to content

About

A cool app to count up or down that writes text to file for streamers

Topics

Resources

Stars

104 stars

Watchers

9 watching

Forks

Repository files navigation

My Stream Timer

My Stream Timer is an easy to use countdown and count-up timer for streamers. Multiple timers are available that write a file to disk to use with OBS, SLOBS, or your favorite streaming application. Have it auto start so it works with Stream Deck!

Download today on Windows or macOS:

The Windows app is distributed exclusively through the Microsoft Store (Pro features use Store licensing). A vX.Y.Z-windows tag starts the Windows Store Publish workflow, which submits to a tester package flight after protected-environment approval. Manual runs also support direct production submission or promotion of an existing run's exact package, including PDBs, without rebuilding. Tags never submit directly to production. See Windows release flows.

What's new in 3.0 (Windows)

My Stream Timer for Windows was rewritten from the ground up in WinUI 3 / Windows App SDK with a modern Fluent design. Everything you had configured before — timer settings, file names, output folder and Pro unlocks — carries over automatically.

  • Sidebar navigation, Mica, Light/Dark/System themes
  • Rename timers and pick an icon for each one (Settings › Timers)
  • Pop‑out timer windows (Pro) with custom font, size and colours — great on a second monitor or pinned over OBS
  • Automation page with a command builder that generates mystreamtimer:// URLs for Stream Deck and scripts
  • Output folder management (choose, test access, open in Explorer), per‑timer +1 / −1 minute, keyboard shortcuts (Space start/stop, P pause, R reset, Ctrl+Shift+1…7 switch timers)
  • Pro subscriptions (monthly / 6 months) in addition to the lifetime tiers
  • New automation host: mystreamtimer://time/?start and ?stop for the clock timer
  • Keeps your PC awake while a timer is running — no more "do not minimize" warning

Integrating into OBS/SLOBS

Open My Stream Timer and tap the copy icon to copy the location on disk where My Stream Timer saves output files.

Next, Open OBS/SLOBS and add a Text source. Check "Read from file" and click browse and navigate location that was copied to the clipboard. Select on of the text files for count down, up, or giveaway. That's it! When you start the countdown it will show up!

If you are on macOS when you set click "Browse" in OBS/SLOBS the file picker will come up. To browse to a folder use the following command on your keyboard: (CMD + SHIFT + G) and then paste the directory from My Stream Timer

End sounds

Every countdown and count-up timer has its own sound settings on its timer page, so each timer can use a different sound. Choose Default beep, Chime, Bell, Digital, or Custom, and use Preview to hear it. The four built-in sounds are original synthesized WAV files included with each app; Default beep uses the classic three-beep pattern.

  • Countdowns: turn on Beep at zero to play the timer's sound when it finishes.
  • Count ups: turn on Play sound at time and set the minutes and seconds. The sound plays once when the count up reaches that time, and the timer keeps counting. Resuming a paused count up that is already past the time does not replay the sound.

For Custom, choose an MP3 or WAV file (.mp3, .wav, or .wave) for that timer. The selection is saved between app launches. Keep the file available in its selected location; if it cannot be played, the app falls back to Default beep.

Menu bar timers (macOS, Pro)

On macOS, any timer can have its own menu bar item. Turn on Show in menu bar on a timer's page, or pick several at once under Settings › Menu bar timers.

  • An idle timer shows its icon. A running timer shows the icon and the timer's output, in the format you set for it, so it matches the timer's output file. A paused timer shows a pause icon with the output it stopped at. Output longer than 32 characters is cut off with an ellipsis.
  • Click the item to start, stop, pause, resume, add a minute, reset, open the app on that timer, or hide the item.
  • While at least one timer is in the menu bar, My Stream Timer keeps running after you close its window, and timers keep writing their output files. Use Quit My Stream Timer in the menu to quit.

Integrating into Stream Deck

The official My Stream Timer plugin is in MyStreamTimer.StreamDeck. It provides configurable actions for every countdown, count-up, and Current Time output, including start, add/subtract, pause, resume, reset, and stop. A Start Timer action can also run an independent countdown that writes directly to a text file without launching the app.

Plugin releases are attached to GitHub tags such as v2.0.0-streamdeck. Existing buttons from the legacy plugin must be removed and re-added because version 2 uses new plugin and action identifiers.

You can also integrate a Website command under System using a protocol URL:

  • Count down from X minutes: mystreamtimer://countdown/?mins=6
  • Count down to specific time (24 hour clock): mystreamtimer://countdown/?to=15:30
  • Count down to top of the hour: mystreamtimer://countdown/?topofhour

Integrating into Command Line

My Stream Timer uses standard protocals to work via the command line. For example you can call the following on the Windows command line:

start mystreamtimer://countdown/?mins=6

Here are the list of commands:

  • mystreamtimer://countdown/?mins=6
  • mystreamtimer://countdown/?secs=90
  • mystreamtimer://countdown/?topofhour
  • mystreamtimer://countdown/?to=15:30
  • mystreamtimer://countdown/?addmins=1 · ?addsecs=30 · ?subtractmins=1 · ?subtractsecs=30
  • mystreamtimer://countdown/?pause · ?resume · ?reset · ?stop
  • mystreamtimer://time/?start · ?stop (clock timer, Pro)

countdown can be replaced with: countdown2, countdown3, countdown4, countup, countup2 depending on which one you would like to control. The Automation page in the app builds these URLs for you.

Integrating into Deckboard (using an Extension App for Windows)

If you do not own a Stream Deck but use other apps to control your stream, Dara Oladapo created an extension app for Windows that he uses for Deckboard. You can check out the project here and web link here.

In Action

View the walkthrough on YouTube

Building from source (Windows)

Requires the .NET 10 SDK, the WinApp CLI and Developer Mode.

dotnet test tests\MyStreamTimer.Core.Tests
dotnet build src\MyStreamTimer.WinUI\MyStreamTimer.WinUI.csproj -p:Platform=x64
cd src\MyStreamTimer.WinUI && dotnet run

Debug builds install side‑by‑side with the Store app under a *.Dev identity (protocol mystreamtimer-dev://). Release builds use the Store identity. The migration plan, design spec and upgrade‑test checklist live in winui-migration/.

ImageSharp is used only by the optional icon generator developer tool to regenerate icon assets. It is not an app dependency and is not part of the normal solution build; the app uses the generated assets checked into source control.

Troubleshooting

My Stream Timer should work out of the box, but if it doesn't here are some tips and tricks.

Windows: Crashes or the app will not open

If the app opens, go to About > Diagnostics > Save diagnostics report. Choose a local ZIP file, review it, and share it privately with support. Nothing is uploaded automatically. The report contains bounded startup/failure records, exception types, HRESULTs, stacks, and app/OS/runtime versions. It excludes exception messages, timer content, output files, settings databases, and account/licensing information. Historical plain-text crash logs are not included automatically because they can contain private paths or text.

Open crash logs folder also opens the local diagnostics directory. If the app cannot open, paste this path into Explorer:

%LOCALAPPDATA%\Packages\23875RefractoredLLC.MyStreamTimer_jcspp7mzn01xr\LocalState\logs

Older 3.0/3.1 builds may have crash-*.txt files there. New builds retain at most six structured diagnostic files of up to 128 KiB each, including a per-process session ID. Review any older logs before sharing them. Do not uninstall or reset the app to collect logs; doing so can remove settings and evidence.

Invalid timer commands and unavailable diagnostic reports are reported without deliberately throwing. Recoverable export failures show an error instead of claiming a report was saved. If an exception reaches the managed entry point, the app records it, shows an error, and exits with a failure code rather than rethrowing. This does not make native fail-fast or other fatal framework failures recoverable, and the app does not mark all unhandled XAML exceptions as safe to ignore. Do not deliberately crash a live app to test diagnostics.

During shutdown, cleanup failures are recorded as shutdown-step-failed, shutdown-failed, or popout-close-failed; remaining cleanup and the final window close are still attempted. A timer drain exceeding five seconds records shutdown-timeout. If the final window close itself throws, the app records shutdown-close-failed and exits with a failure code rather than leaving an unusable window open. Copy-feedback timers are stopped when their page unloads, and their callbacks do not update the UI after shutdown begins.

Failures before the .NET runtime starts and native fail-fast crashes may leave no application log. In Reliability Monitor or Event Viewer > Windows Logs > Application, look for MyStreamTimer.exe at the failure time. Useful details include the faulting module, exception code, app version, and full Windows build/revision. Relevant events commonly include Application Error 1000, .NET Runtime 1026, and Windows Error Reporting 1001. Startup-only failures can also require the AppModel-Runtime and AppXDeploymentServer event channels. Share only app-specific entries, not an export of all machine events.

Build 10.0.26200 is Windows 11 25H2, not Windows 10. Include the complete revision, such as 26200.x, when reporting a failure.

Optional: capture a crash dump on a test machine

Only enable this when support needs native/early crash evidence. Dumps can contain private process memory; do not post them to public GitHub issues. The following administrator PowerShell commands enable full dumps for this executable only, not for every application:

$key = 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyStreamTimer.exe'
if (Test-Path -LiteralPath $key) {
    throw 'Existing per-app dump settings found. Preserve them before changing anything.'
}
New-Item -Path $key -Force | Out-Null
New-ItemProperty -Path $key -Name DumpType -PropertyType DWord -Value 2 | Out-Null
New-ItemProperty -Path $key -Name DumpCount -PropertyType DWord -Value 3 | Out-Null

Reproduce the problem with consent on the test machine, then check %LOCALAPPDATA%\CrashDumps. Missing-runtime exits are not necessarily crashes, so they might not create a dump. Automatic debugger settings can also prevent WER LocalDumps collection. For opaque WinUI errors, analyze native/stowed exceptions with WinDbg or use the WinApp CLI's attached --debug-output diagnostics; an app log alone cannot decode native fail-fast failures.

After collection, remove only the per-app key created above to restore the previous configuration:

Remove-Item -LiteralPath 'HKLM:\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyStreamTimer.exe'

See Microsoft's LocalDumps guidance for collection limitations.

Windows: flight-first releases

Configure flighting before publishing a new Windows tag:

  1. Set the GitHub Actions repository variable MICROSOFT_STORE_FLIGHT_GROUP_IDS to comma-separated Partner Center tester group IDs (for example, the IAP Test known user group ID). If the app has no package flights, an approved flight publish creates Internal Testing through the Store API with these groups. Existing flights and their tester groups are reused unchanged. Group names are not group IDs or package flight IDs.
  2. Keep MICROSOFT_STORE_PRODUCT_ID and the Partner Center credentials configured as described in the publishing setup. The existing microsoft-store environment approval still gates submissions.
  3. If the app has exactly one package flight, no flight ID configuration is needed. After authentication, the workflow queries the Store submission API, reads all pages, and logs the flight's name, ID, and group IDs. With multiple flights, set the optional GitHub Actions repository variable MICROSOFT_STORE_FLIGHT_ID to the intended package flight ID shown in those logs. Do not use a group ID, group name, or flight display name. The configured ID must match an existing flight for this app.

Windows tag pushes always submit to that selected flight. Manual runs default to destination = flight; selecting production explicitly submits to the public Store instead, without needing a flight. Empty or whitespace-only flight ID overrides use automatic discovery. Missing flights without valid tester group configuration, multiple flights without an override, invalid overrides, and discovery errors fail a flight job; there is no production fallback. Each subsequent flight release submits to the same flight.

Flight publication checks pending submissions before uploading. Processing submissions block publication. A portal-created draft without an API upload URL also blocks publication: discard only that unsubmitted draft in Partner Center, or manually run a flight publish with replace_flight_draft = true to remove only a PendingCommit portal draft. The flight and tester groups are preserved; API-ready drafts are not deleted. Tag pushes never authorize draft deletion.

In Actions > Windows Store Publish > Run workflow, select main (or the intended release source) and use:

Flow tag destination publish source_run_id release_notes
Build artifacts only New version, e.g. v3.2.1-windows flight false Empty Optional; saved for later
Build -> Flight New version flight true Empty Recommended; saved for promotion
Flight -> Release (no rebuild) Empty production true Successful Store Publish run ID Empty to reuse saved notes, or enter replacement text
Build -> Release New version production true Empty Required

Leave diagnose_only = false for these flows. The tag input stamps the version; it does not check out or create that tag. The selected workflow ref supplies the source. To check credentials without building/submitting, use diagnose_only = true; flight mode also discovers the flight when the product ID is configured, while production mode does not require flight discovery. Diagnostics never create flights or delete drafts; before the first flight exists, discovery reports that no flights were found.

The source run ID is the numeric part of its Actions URL (.../actions/runs/123456789). Promotion accepts only a completed, successful Windows Store Publish run from this repository's default branch or a Windows release tag with exactly one unexpired windows-store-package artifact. A build-only run can also be reused. It downloads that run's complete .msixupload, revalidates x64/ARM64 and matching PDBs, logs the SHA-256, and submits the same bytes; it never changes the package version or rebuilds the tested code. Both the original flight and production submission require separate microsoft-store approvals. Run success means submission succeeded, not that Store certification finished: confirm the flight is certified and test it before promoting. Packages/notes are retained for 90 days; retain the original run's matching symbols/provenance artifact too. Expired artifacts require manual Partner Center promotion or an original retained upload, not an arbitrary rebuild.

What's new: release_notes accepts up to 1,500 characters. The workflow saves it as release-notes.txt alongside the package. Flights have no separate public listing, so their notes are held for promotion. Production requires nonempty notes (entered or inherited), uploads a draft first, updates and verifies the existing English listing(s), then commits the submission. Other translations, descriptions, packages, pricing, and release scheduling remain unchanged. Existing English platform-specific release-note overrides are updated too. For an older source run without saved notes, enter them when promoting. An existing pending production submission blocks automated release rather than being overwritten. Metadata failures leave the new draft uncommitted for investigation; review it in Partner Center before retrying.

After the flight passes Store certification, its testers receive the Store update under the existing app identity; other customers remain on the public version. Test upgrades, startup, timer/automation behavior, and purchases with those accounts before promoting. The workflow retains the complete symbol-validated upload and logs its SHA-256.

Manual promotion is still available: create a regular (non-flighted) submission in Partner Center, and on Packages copy the same tested packages from the published flight. Review the normal release settings and submit for production certification; do not rebuild just to promote. Flight certification can relax some WACK checks, so it does not replace production certification. See Microsoft's package flights guidance and the Store CLI publish options.

This routing applies to runs using the updated workflow. It does not redirect submissions from older tags or already-running releases.

Windows: validating a Store release

Store builds bundle the architecture-specific .NET runtime while retaining the Store-managed Windows App Runtime dependency. These are separate runtimes. The retained 3.0/3.1 uploads were .NET-framework-dependent, so a missing compatible .NET 10 runtime is a startup-failure candidate, not proof of the cause of any Partner Center crash bucket.

The Store publishing workflow validates the final x64/ARM64 bundle with Test-StorePackage.ps1, checks bundled runtime files, native architecture and configuration, verifies portable PDB identifiers against each application's binaries, and retains matching symbols and build provenance alongside the upload artifact. Store symbol generation also requires the Visual C++ symbol tools (mspdbcmf.exe); the Windows CI image supplies them and the workflow locates them explicitly. Retain/download those CI artifacts for the release you investigate; a later rebuild's symbols are not automatically interchangeable.

Symbols are submitted inside the .msixupload, alongside the app bundle, as .appxsym archives. The Store project explicitly generates portable PDBs in Release builds. After downloading the artifact, the publishing job revalidates the exact file, refuses missing/mismatched symbols or ambiguous upload candidates, logs its SHA-256, and passes the complete .msixupload to msstore publish. The separate GitHub symbols artifact is an investigation backup, not the mechanism that sends symbols to Microsoft. For manual Partner Center submissions, upload the .msixupload, not just the inner .msixbundle; see Microsoft's Store upload guidance.

The retained 3.0/3.1 uploads omitted symbols. These safeguards take effect only in a release built and submitted with the updated workflow; they do not establish that Microsoft has symbols for already-published versions. Historical investigation requires symbols matching those exact release binaries, not an arbitrary rebuild.

Partner Center's Health report uses daily device-based crash rates from devices sharing optional diagnostics, not a per-launch rate. Compare compatible app-version/OS/architecture cohorts and denominators. Generic uncategorized failures can reflect missing reports, while !unknown function names can reflect missing symbols; adding symbols cannot recover a dump that was never collected.

Windows: repeatable randomized smoke tests

The Core suite includes four fixed random seeds, each exercising 25,000 operations across all seven timer kinds. It mixes protocol parsing, malformed/extreme numeric values, direct commands, start/stop/pause/resume/reset, settings changes and clock advancement. Failures include the seed and recent operations; background timer faults and final idle/power-activity state are checked. The clocks, output files and platform hooks are test doubles; these are not 100,000 packaged UI actions.

dotnet test tests\MyStreamTimer.Core.Tests\MyStreamTimer.Core.Tests.csproj -c Release --filter FullyQualifiedName~RandomizedCommandTests --logger trx

For packaged UI/activation stress, first register and launch an isolated, uniquely named development test package, with its own protocol and output data. Do not target the Store or normal Dev installation. Then run Test-WindowsRandomizedSmoke.ps1, supplying that package's exact PID, identity and protocol:

.\scripts\Test-WindowsRandomizedSmoke.ps1 `
    -AppPid <test-process-id> `
    -PackageName 'RefractoredLLC.MyStreamTimer.SmokeTest<unique-suffix>' `
    -Protocol 'mystreamtimer-smoketest<unique-suffix>' `
    -ResultsDirectory '<absolute-test-results-directory>' `
    -Seed 63801 -Iterations 120 -MaximumSeconds 600

The script refuses non-test identities and mismatched PIDs/protocols. It randomizes navigation, enabled timer/dashboard controls, duration edits, Automation runs, and app themes, interleaving bounded ten-launch protocol bursts. It records the seed, actual UI-call and protocol-launch-attempt counts, disabled actions skipped, diagnostic failures, timeout failures, and screenshots. Each UI command has a 15-second limit. It does not make purchases, invoke external links, inject crashes, or unregister the app; close and remove only the temporary test registration afterward.

Review screenshots as well as results. A passing local run is not proof that every activation was delivered, that every thread schedule was tested, or that clean Windows build 26200 deployment and Store upgrades work.

Debugger first-chance exception notifications alone are not crashes: an exception may be caught, including normal task cancellation. Check unhandled/timer-failure records, process exits, and timeouts separately; a successful smoke run does not mean no caught exceptions occurred.

Known harness limitation: UI Automation elements can become stale across navigation/theme changes. Treat a driver error separately from an application crash; retain the failed result and do not call it a green UI sign-off even if all randomized actions completed.

macOS: Defensive timer command handling

The native Swift app already ignores adjustments before the first start and after stopping; it does not share the Windows uninitialized-date subtraction bug. Numeric automation durations must be finite and representable by the integer-second output formatters. Invalid starts, resets, and adjustments report an error without replacing a running or paused timer. Extreme stored duration values are validated without overflowing integer arithmetic.

The timer actor also checks intervals before formatting, reports invalid timing as a failure rather than normal completion, and bounds sleeps for long static countdowns. This is defensive validation, not a blanket recovery handler for fatal native failures. Windows-specific .NET deployment and WinUI entry-point changes do not apply to the native Swift app.

On a Mac with Xcode 26.2, run the existing macOS build/test gate (also in macos-build.yml):

xcodebuild test \
  -project MyStreamTimer.MacSwift/mystreamtimer/mystreamtimer.xcodeproj \
  -scheme mystreamtimer -configuration Debug -destination 'platform=macOS' \
  CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO

Regressions cover invalid numeric URLs, cold/stopped adjustments, preserving active/paused timers on rejected commands, integer settings boundaries, count-up zero, long static countdown scheduling, and large day counts. These macOS tests require Xcode; a Windows Core test pass does not validate the Swift app.

macOS: Files can't be saved

In some instances My Stream Timer may need full file accessed based on your setup (This is rare). Head to Preferences > Security & Privacy > Full Disk Access Unlock to add My Stream Timer from your application folder.

Adding my stream timer to full disk access

macOS: I dont' hear any "beeps"

Enable Beep at zero (or Play sound at time for a count up) on the timer, then use Preview next to that timer's sound. Check your system output device and volume in System Settings > Sound. End sounds play as app audio rather than using the system alert sound. If a custom file is no longer accessible or cannot be decoded, choose it again or select a built-in sound.

About

A cool app to count up or down that writes text to file for streamers

Topics

Resources

Stars

104 stars

Watchers

9 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages