Skip to content

feat: add Open-Meteo provider and configurable weather cache#11

Merged
Small-tailqwq merged 8 commits into
Small-tailqwq:masterfrom
Tim-Devil:openmeteo-cache-provider
Jun 14, 2026
Merged

feat: add Open-Meteo provider and configurable weather cache#11
Small-tailqwq merged 8 commits into
Small-tailqwq:masterfrom
Tim-Devil:openmeteo-cache-provider

Conversation

@Tim-Devil

@Tim-Devil Tim-Devil commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Changes

  • Add Open-Meteo as a keyless weather provider using configured latitude/longitude.
  • Add CacheExpiryMinutes to replace the hard-coded 60-minute weather cache TTL.
  • Keep the existing cache-driven scheduler: valid cache delays the next check until cache expiry; F7 still bypasses cache.
  • Retry daily sunrise/sunset sync after a successful weather fetch when LastSunSyncDate is still stale.

Notes

  • Existing Seniverse provider remains available.
  • Weather cache stays in memory; Sunrise/Sunset continue to be persisted in config.

Validation

  • dotnet build could not run in this environment because .NET Framework 4.7.2 targeting pack is missing.
  • dotnet test could not run in this environment because only .NET SDK 6.0 is installed while tests target net9.0.

Copilot AI review requested due to automatic review settings June 13, 2026 13:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds support for the Open-Meteo weather provider alongside Seniverse, with configurable caching and improved sun schedule syncing behavior.

Changes:

  • Added Open-Meteo fetch + parsing paths for weather and sunrise/sunset.
  • Made cache expiry configurable and introduced provider-aware cache keys.
  • Added provider/lat/long config options and guarded sun sync from overlapping runs.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
RealTimeWeatherMod/Services/WeatherService.cs Adds provider routing (OpenMeteo vs Seniverse), caching tweaks, Open-Meteo parsing, and LastFetchSucceeded.
RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs Maps Open-Meteo fields into existing WeatherInfo/condition semantics.
RealTimeWeatherMod/RealTimeWeather.csproj Includes the new Open-Meteo mapper in compilation.
RealTimeWeatherMod/Core/AutoEnvRunner.cs Uses provider-aware “usable key” check; prevents concurrent sun sync; gates sun sync on LastFetchSucceeded.
RealTimeWeatherMod/ChillEnvPlugin.cs Adds config entries: provider selection, cache expiry, and Open-Meteo coordinates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 90 to 99
public static IEnumerator FetchWeather(string apiKey, string location, bool force, Action<WeatherInfo> onComplete)
{
string normalizedLocation = NormalizeLocation(location);
LastFetchSucceeded = false;
string cacheKey = GetCacheKey(location);

if (!force && HasValidCacheNormalized(normalizedLocation))
if (!force && HasValidCacheNormalized(cacheKey))
{
onComplete?.Invoke(_cachedWeather);
yield break;
}
Comment on lines +32 to +35
private static int GetCacheExpiryMinutes()
{
return ChillEnvPlugin.Cfg_CacheExpiryMinutes != null ? ChillEnvPlugin.Cfg_CacheExpiryMinutes.Value : 60;
}
Comment on lines +60 to +63
private static bool HasValidCacheNormalized(string cacheKey)
{
return HasAnyCacheNormalized(cacheKey) &&
DateTime.Now - _lastFetchTime < TimeSpan.FromMinutes(GetCacheExpiryMinutes());
onComplete?.Invoke(fallback);
}
}
catch { onComplete?.Invoke(fallback); }
}
}
catch { onComplete?.Invoke(null); }
catch { onComplete?.Invoke(fallback); }
Comment on lines +248 to +251
private static WeatherInfo ParseOpenMeteoWeatherJson(string json)
{
string current = ExtractObject(json, "\"current\":{");
if (string.IsNullOrEmpty(current)) return null;
Comment on lines +455 to +460
private static string ExtractObject(string json, string prefix)
{
int start = json.IndexOf(prefix, StringComparison.Ordinal);
if (start < 0) return null;
start += prefix.Length - 1;

Comment on lines 112 to 115
private System.Collections.IEnumerator SyncSunScheduleRoutine(string targetDate)
{
_isSunSyncRunning = true;
int retryCount = 0;
Comment on lines 140 to 144
if (success)
{
_isSunSyncRunning = false;
yield break;
}
Comment on lines +153 to +154
ChillEnvPlugin.Log?.LogError("[SunSync] 达到最大重试次数,今日放弃同步");
_isSunSyncRunning = false;
@Small-tailqwq

Copy link
Copy Markdown
Owner

/review

@Tim-Devil

Tim-Devil commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

/review

please wait for a bit. I have fixed some parts. Will update now. Same Commit and PR.

update: Done. Please check for new fix. Thanks!

@Small-tailqwq

Copy link
Copy Markdown
Owner

/review

1 similar comment
@Small-tailqwq

Copy link
Copy Markdown
Owner

/review

@Tim-Devil

Copy link
Copy Markdown
Contributor Author

Thanks for triggering /review again. I checked the Actions page and the latest issue_comment run completed successfully, but it seems did not add any new PR review summary or inline comments. The Checks tab still shows the earlier pull_request_target review run as cancelled on current head.

It looks like the /review workflow is running, but its result is not being reflected back on the PR. I can open a fresh PR from the same latest branch so the pull_request_target workflow can run from a clean PR-open event, if that works for you.

@Small-tailqwq

Small-tailqwq commented Jun 13, 2026

Copy link
Copy Markdown
Owner

CI爆炸了,别慌,战术性调整
CI blew up, don't panic, tactical adjustment

@Small-tailqwq

Copy link
Copy Markdown
Owner

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 OpenCodeReview found 8 issue(s).

  • ✅ 7 inline comment(s)
  • 📝 1 in summary

📄 RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs

The hard-coded integer weather codes (21, 11, 14, 13, 26, 4, 1) used throughout as return values and comparisons reduce readability and make the mapping fragile to changes. Consider defining named constants (e.g., private const int SeniverseSnow = 21) or an enum aligned with the Seniverse code system. This would make the mapping intent self-documenting and easier to maintain alongside WeatherService.MapCodeToCondition.

💡 Suggested Change
            // Seniverse codes: 1=Clear, 4=Cloudy, 11=Thunder, 13=LightRain, 14=HeavyRain, 21=Snow, 26=Fog
            if (snowfall > 0d || IsSnow(weatherCode))
            {
                return 21;
            }

            if (IsThunder(weatherCode))
            {
                return 11;
            }

            if (IsHeavyRain(weatherCode) || precipitation >= 2.5d || rain + showers >= 2.5d)
            {
                return 14;
            }

            if (IsLightRain(weatherCode) || precipitation > 0d || rain > 0d || showers > 0d)
            {
                return 13;
            }

            if (weatherCode == 45 || weatherCode == 48)
            {
                return 26;
            }

            if ((weatherCode >= 1 && weatherCode <= 3) || cloudCover >= 65d)
            {
                return 4;
            }

            return 1;

Comment thread RealTimeWeatherMod/Core/AutoEnvRunner.cs
Comment thread RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs Outdated
Comment thread RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs
Comment thread RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs
Comment thread RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs Outdated
Comment thread RealTimeWeatherMod/Services/WeatherService.cs
Comment thread RealTimeWeatherMod/Services/WeatherService.cs
Tim-Devil and others added 4 commits June 13, 2026 23:51
Remove the cloudCover >= 65d override.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Reuse WeatherService.MapCodeToCondition(normalizedCode)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Change the fallback text from "OpenMeteo" to $"OpenMeteo({weatherCode})"

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Comment thread RealTimeWeatherMod/Core/AutoEnvRunner.StartupSync.cs Outdated
Comment thread RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs Outdated
Comment thread RealTimeWeatherMod/Core/AutoEnvRunner.cs
Comment thread RealTimeWeatherMod/Services/WeatherService.cs
Comment thread RealTimeWeatherMod/Services/WeatherService.cs
Comment thread RealTimeWeatherMod/Services/WeatherService.cs
@github-actions

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 9 issue(s).

  • ✅ 7 inline comment(s)
  • 📝 2 in summary

📄 RealTimeWeatherMod/Core/AutoEnvRunner.cs

SyncSunScheduleRoutine no longer retries on failure. A single transient network error will delay sun sync until the next weather refresh interval (default 30 min). Consider adding at least 1–2 retries with a short backoff before giving up for the interval, or use a dedicated, shorter retry window for sun sync independent of the weather refresh cycle.

💡 Suggested Change
        private System.Collections.IEnumerator SyncSunScheduleRoutine(string targetDate)
        {
            const int maxRetries = 3;
            float delay = 2f;

            for (int attempt = 0; attempt < maxRetries; attempt++)
            {
                bool success = false;
                string apiKey = ChillEnvPlugin.Cfg_SeniverseKey.Value;
                string location = ChillEnvPlugin.Cfg_Location.Value;

                yield return WeatherService.FetchSunSchedule(apiKey, location, (data) =>
                {
                    if (data != null)
                    {
                        ChillEnvPlugin.Log?.LogInfo($"[SunSync] 同步成功: 日出{data.sunrise} 日落{data.sunset}");

                        ChillEnvPlugin.Cfg_SunriseTime.Value = data.sunrise;
                        ChillEnvPlugin.Cfg_SunsetTime.Value = data.sunset;
                        ChillEnvPlugin.Cfg_LastSunSyncDate.Value = targetDate;

                        ChillEnvPlugin.Instance.Config.Save();
                        success = true;
                    }
                });

                if (success)
                {
                    yield break;
                }

                if (attempt < maxRetries - 1)
                {
                    ChillEnvPlugin.Log?.LogWarning($"[SunSync] 同步失败,{delay}秒后重试 ({attempt + 1}/{maxRetries})");
                    yield return new WaitForSeconds(delay);
                    delay *= 2f;
                }
            }

            ChillEnvPlugin.Log?.LogWarning("[SunSync] 同步失败,保留现有日出日落设置");
        }

📄 RealTimeWeatherMod/Core/AutoEnvRunner.cs (L227)

⚠️ Failed to post inline: Unprocessable Entity: "Line could not be resolved"

TriggerSunScheduleRefresh bypasses the CheckAndSyncSunSchedule guards (HasUsableApiKey, throttling, enable flags). This can cause API calls even when no provider is configured. Consider routing through CheckAndSyncSunSchedule or at minimum adding the HasUsableApiKey guard before starting the coroutine.

Comment thread RealTimeWeatherMod/Services/WeatherService.cs
@Small-tailqwq

Small-tailqwq commented Jun 13, 2026

Copy link
Copy Markdown
Owner

😰bot发狂了
好像是ci的触发器太宽松了,回头改改
太晚了要歇逼了,明天我调试调试,没啥问题我直接合了吧。早点休息

@Tim-Devil

Copy link
Copy Markdown
Contributor Author

OK bro, I think the first advice copilot given is actually good and will apply. Others are just some AI trash :(

Wish you a good sleep ^^

Tim-Devil and others added 2 commits June 14, 2026 00:28
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Comment on lines +114 to +122
private static string ToWeatherText(int weatherCode, int normalizedCode)
{
if (normalizedCode == 21) return "Snow";
if (normalizedCode == 11) return "ThunderRain";
if (normalizedCode == 14) return "HeavyRain";
if (normalizedCode == 13) return "LightRain";
if (normalizedCode == 26) return "Fog";
if (normalizedCode == 4) return "Cloudy";
return weatherCode == 0 ? "Clear" : "Unknown";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ToWeatherText uses the raw weatherCode in its fallback, which can produce "Unknown" when normalizedCode=1 but weatherCode≠0. Meanwhile, ToCondition(1) returns WeatherCondition.Clear via MapCodeToCondition, creating an inconsistency. Add an explicit case for normalizedCode=1 so the text is fully determined by the normalized code, and consider logging a warning for unrecognized weatherCode values.

Suggestion:

Suggested change
private static string ToWeatherText(int weatherCode, int normalizedCode)
{
if (normalizedCode == 21) return "Snow";
if (normalizedCode == 11) return "ThunderRain";
if (normalizedCode == 14) return "HeavyRain";
if (normalizedCode == 13) return "LightRain";
if (normalizedCode == 26) return "Fog";
if (normalizedCode == 4) return "Cloudy";
return weatherCode == 0 ? "Clear" : "Unknown";
private static string ToWeatherText(int weatherCode, int normalizedCode)
{
if (normalizedCode == 21) return "Snow";
if (normalizedCode == 11) return "ThunderRain";
if (normalizedCode == 14) return "HeavyRain";
if (normalizedCode == 13) return "LightRain";
if (normalizedCode == 26) return "Fog";
if (normalizedCode == 4) return "Cloudy";
if (normalizedCode == 1) return "Clear";
return "Unknown";

{
Code = normalizedCode,
Text = ToWeatherText(weatherCode, normalizedCode),
Temperature = (int)Math.Round(temperature),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Math.Round without a MidpointRounding argument defaults to banker's rounding (round-to-even). For example, 2.5°C rounds to 2 and 3.5°C rounds to 4, which can be counterintuitive for weather display. Consider using MidpointRounding.AwayFromZero for temperatures: Math.Round(temperature, MidpointRounding.AwayFromZero).

Suggestion:

Suggested change
Temperature = (int)Math.Round(temperature),
Temperature = (int)Math.Round(temperature, MidpointRounding.AwayFromZero),

return 4;
}

return 1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When no conditions match, ToSeniverseCode silently returns 1 (Clear). Unrecognized weather codes are effectively hidden, making it harder to detect API changes or mapping gaps during development. Consider logging a warning via ChillEnvPlugin.Log?.LogWarning(...) when an unmapped code is encountered, or alternatively have the caller in WeatherService.ParseOpenMeteoWeatherJson validate the result.

Suggestion:

Suggested change
return 1;
// Fallback: treat as clear. Log a warning if the weatherCode was not explicitly 0.
if (weatherCode != 0)
{
ChillEnvPlugin.Log?.LogWarning($"[OpenMeteo] Unmapped weather code {weatherCode}, falling back to Clear");
}
return 1;

Comment on lines +183 to +188
if (request.result != UnityWebRequest.Result.Success || string.IsNullOrEmpty(request.downloadHandler.text))
{
ChillEnvPlugin.Log?.LogWarning($"[OpenMeteo] 请求失败: {request.error}");
onComplete?.Invoke(fallback);
yield break;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observability gap: no log when fallback cache is served. When a weather fetch fails (network error or parse failure), onComplete?.Invoke(fallback) is called with the previous cached data. The failure itself is logged ("[API] 请求失败" / "[OpenMeteo] 解析失败"), but there is no corresponding informational message indicating that stale cached data is being returned. In noisy logs, the failure warning can be overlooked, and the caller has no way to distinguish "fresh data" from "stale fallback" without comparing the returned WeatherInfo to CachedWeather. Consider adding a log like "[OpenMeteo] 使用缓存数据作为回退" to make this path observable.

Suggestion:

Suggested change
if (request.result != UnityWebRequest.Result.Success || string.IsNullOrEmpty(request.downloadHandler.text))
{
ChillEnvPlugin.Log?.LogWarning($"[OpenMeteo] 请求失败: {request.error}");
onComplete?.Invoke(fallback);
yield break;
}
if (request.result != UnityWebRequest.Result.Success || string.IsNullOrEmpty(request.downloadHandler.text))
{
ChillEnvPlugin.Log?.LogWarning($"[OpenMeteo] 请求失败: {request.error}");
if (fallback != null) ChillEnvPlugin.Log?.LogInfo("[OpenMeteo] 使用缓存数据作为回退");
onComplete?.Invoke(fallback);
yield break;
}

@github-actions

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 11 issue(s).

  • ✅ 4 inline comment(s)
  • 📝 7 in summary

📄 RealTimeWeatherMod/Core/AutoEnvRunner.cs

Retry logic removed. The old SyncSunScheduleRoutine had up to 10 retries with exponential backoff. Now a single transient failure means the next sun sync attempt won't happen until CheckAndSyncSunSchedule is called again after the configured weather refresh interval (default 30 min). Consider adding at least 2–3 fast retries (e.g., 1s, 3s, 5s) before giving up, since sunrise/sunset data changes only once per day and is critical for correct time-based environments.

private System.Collections.IEnumerator SyncSunScheduleRoutine(string targetDate)
{
    const int maxRetries = 3;
    float delay = 1f;
    for (int i = 0; i < maxRetries; i++)
    {
        bool success = false;
        // ... existing fetch logic ...
        yield return WeatherService.FetchSunSchedule(apiKey, location, (data) =>
        {
            if (data != null) { /* store */ success = true; }
        });
        if (success) yield break;
        if (i < maxRetries - 1)
        {
            yield return new WaitForSeconds(delay);
            delay *= 2f;
        }
    }
    ChillEnvPlugin.Log?.LogWarning("[SunSync] 同步失败,保留现有日出日落设置");
}

📄 RealTimeWeatherMod/Core/AutoEnvRunner.cs

CRITICAL: This lambda is syntactically broken. The first { at line 473 has no matching } before (weather) => at line 479. The nested lambda is invalid C# — it appears you merged two versions of the callback. This will prevent the project from compiling. The fix is to use a single callback that includes CheckAndSyncSunSchedule():

(weather) =>
{
    _startupWeatherFetchFinished = true;
    if (weather != null)
    {
        _pendingStartupWeather = weather;
        UpdateUiWeatherString(weather);
    }
    CheckAndSyncSunSchedule();
}
💡 Suggested Change
(weather) =>
                    {
                        _startupWeatherFetchFinished = true;
                        if (weather != null)
                        {
                            _pendingStartupWeather = weather;
                            UpdateUiWeatherString(weather);
                        }
                        CheckAndSyncSunSchedule();
                    }));

📄 RealTimeWeatherMod/Core/AutoEnvRunner.cs

CheckAndSyncSunSchedule() is called in 6 different branches across AutoEnvRunner.cs and StartupSync.cs. While the _nextSunSyncAttemptTime guard prevents duplicate work at runtime, the scattered placement is brittle — future code paths could easily miss the call. Consider refactoring so that sun sync is triggered from a single centralized point (e.g., after HasValidCache or LastFetchSucceeded transitions), or by exposing a single OnWeatherDataAvailable() hook that both weather flow and startup sync call.


📄 RealTimeWeatherMod/Services/OpenMeteoWeatherMapper.cs

Snow is checked before Thunder. If both snowfall > 0 and IsThunder is true (e.g., thunderstorm with hail, codes 96/99), the condition is classified as Snow (21) rather than Thunder (11). This may suppress thunder-related game effects in mixed weather. If this priority is intentional (snow visuals take precedence), consider adding a comment to document the rationale.

💡 Suggested Change
            // Snow takes priority over thunder; a thunderstorm with snowfall
            // is treated as snow for visual consistency.
            if (snowfall > 0d || IsSnow(weatherCode))
            {
                return 21;
            }

            if (IsThunder(weatherCode))
            {
                return 11;
            }

📄 RealTimeWeatherMod/Services/WeatherService.cs

CRITICAL: Unresolved merge conflict — this file will not compile. The old lambda body (lines 472–478) was not removed when the new lambda (lines 479–488) was inserted. This creates a nested (weather) => inside the first lambda, and the braces are mismatched (the } on line 489 closes the inner if, but the outer lambda and StartCoroutine call are left with unbalanced braces).

Expected fix: Remove lines 472–478 (the duplicate old body) and fix the brace structure so the final callback reads:

(weather) =>
{
    _startupWeatherFetchFinished = true;
    if (weather != null)
    {
        _pendingStartupWeather = weather;
        UpdateUiWeatherString(weather);
    }
    CheckAndSyncSunSchedule();
}
💡 Suggested Change
                    (weather) =>
                    {
                        _startupWeatherFetchFinished = true;
                        if (weather != null)
                        {
                            _pendingStartupWeather = weather;
                            UpdateUiWeatherString(weather);
                        }
                        CheckAndSyncSunSchedule();
                    }));

📄 RealTimeWeatherMod/Core/AutoEnvRunner.StartupSync.cs (L472)

⚠️ Failed to post inline: Unprocessable Entity: "Line could not be resolved"

Critical: Nested lambda never executes — CheckAndSyncSunSchedule() is dead code.

The code mistakenly contains two nested lambdas. The outer lambda (line 472) is the actual callback passed to FetchWeather, but the inner lambda (line 479) that calls CheckAndSyncSunSchedule() is just a statement creating an unused delegate — it will never be invoked.

This looks like a copy-paste/merge error. The intended change was to add CheckAndSyncSunSchedule() to the existing callback, not to create a second nested lambda.

Fix: Remove the duplicated inner lambda and place CheckAndSyncSunSchedule() directly after the if block inside the outer lambda:

(weather) =>
{
    _startupWeatherFetchFinished = true;
    if (weather != null)
    {
        _pendingStartupWeather = weather;
        UpdateUiWeatherString(weather);
    }
    CheckAndSyncSunSchedule();
}

📄 RealTimeWeatherMod/Services/WeatherService.cs (L292)

⚠️ Failed to post inline: Unprocessable Entity: "Line could not be resolved"

Inconsistency: FetchSeniverseSunSchedule lacks fallback support. The weather fetch methods (FetchSeniverseWeather, FetchOpenMeteoWeather) both accept a fallback parameter and invoke onComplete?.Invoke(fallback) on failure. However, FetchSeniverseSunSchedule still invokes onComplete?.Invoke(null) directly when the API key is missing (line 294) and on request failure (line 309). This means sun schedule has no stale-cache fallback even though the weather path was upgraded to support it. Consider either adding a fallback parameter here too, or documenting that sun schedule intentionally resets to null on failure.

@Small-tailqwq

Copy link
Copy Markdown
Owner

😇先别提交了,我现在没有电脑不好给这bot毙了。而且现有的ci完全不看历史评论的问题,明天我也一并解决掉。

@Tim-Devil

Copy link
Copy Markdown
Contributor Author

Sounds good, I'll wait.

I went through the bot's comments, fixed what actually needed fixing, and left the rest alone. Those are style opinions and design suggestions, nothing that affects correctness.

One thing to flag: I never got to compile any of this. Missing the .NET Framework 4.7.2 targeting pack on my end, and the test project wants .NET 9 while I'm on 6.0. The changes were copilot-assisted too, and that thing needed more babysitting than I'd like to admit. With no build and no tests to catch me, I figured stopping here beats flying blind.

Sorry about that. You'll want to give it a spin in-game yourself. Cache expiry, offline fallback, provider switching, the usual suspects. Oh and take your time with the CI fix tomorrow. Cheers.

@Small-tailqwq Small-tailqwq merged commit 4c52372 into Small-tailqwq:master Jun 14, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants