Conversation
Sync develop with main after v3.6.2
mateof
added a commit
that referenced
this pull request
Apr 14, 2026
* Develop to main (#90) * fix: fix folder creation logic to ensure CurrentFolder is valid before proceeding * fix: solve upload to empty folder and upload to root folder * fix: solve folder problem * Bump version to 3.6.3 --------- Co-authored-by: Mateo <mateof@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
mateof
added a commit
that referenced
this pull request
Jul 22, 2026
* fix: fix folder creation logic to ensure CurrentFolder is valid before proceeding * fix: solve upload to empty folder and upload to root folder * fix: solve folder problem * Sync develop with main after v3.6.3 (#93) * Develop to main (#90) * fix: fix folder creation logic to ensure CurrentFolder is valid before proceeding * fix: solve upload to empty folder and upload to root folder * fix: solve folder problem * Bump version to 3.6.3 --------- Co-authored-by: Mateo <mateof@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: update MongoDB.Driver and System.IO.Hashing package versions * feat: wire progressive download cache into tfm streaming endpoint - StreamAudioByTfmId now starts the background ProgressiveDownloadService download (previously injected but never invoked) so every streamed track is fetched from Telegram once and persisted to the disk cache - Serve ranges from the growing cache file, waiting briefly when the background download is close instead of opening duplicate fetches - Direct Telegram fetches (far seeks) now stream 512KB chunks to the response via new DownloadFileStreamChunks and are limited by a semaphore - Robust Range parsing: TryParse, suffix ranges (bytes=-N), 416 for unsatisfiable ranges, removed ambiguous to==0 sentinel - ProgressiveDownloadService: fix IsRangeAvailable null check, drop stale entries when cache files are evicted, cap retries with backoff, and trim the cache directory to 10GB (oldest first, throttled) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: configurable STRM streaming mode with progressive disk cache Add a 'Streaming Mode' setting (Direct streaming / Progressive cache / Full preload) selectable in the web Config page, used when generating STRM files for Emby/Kodi. - New GetFileStreamCached endpoint: streams from Telegram with Range support while a background download fills the local cache; later ranges and replays are served from disk. - ProgressiveDownloadService now supports split (multi-message) files, caching parts sequentially into a single file with resume support. - Direct seeks ahead of the cache locate the Telegram part containing the requested range and cap the response at the part boundary. - STRM generation picks the endpoint from the configured mode; files smaller than MaxPreloadFileSizeInMb are still fully preloaded. - Backwards compatible with the legacy PreloadFilesOnStream flag (kept in sync on save; used as fallback when the new setting is unset). * fix: show progress and honor cancel for progressive cache downloads The background cache download appeared in the downloads list but never updated its progress and could not be stopped: - Report progress through DownloadModel.ProgressCallback (updates percentage, transmitted/size strings, global speed stats and fires the UI events) instead of writing _transmitted directly. The task is now also marked Completed when the download finishes. - Check the task state on every chunk so pressing Cancel (or Pause) in the downloads list actually stops the background download. - A user cancel is remembered for 1 hour per file so ongoing playback range requests don't immediately restart the cache download; the stream keeps working through direct Telegram fetches. A later playback caches again. - Start the progress counter at the resume offset so resumed downloads don't inflate the global speed stats. - Incomplete downloads no longer linger as 'Working' in the list. * feat: audio transcoding endpoint for offline downloads (MP3/AAC) - GET api/mobile/stream/tfm/{channelId}/{tfmId}/transcoded?format=mp3|aac&bitrate=N downloads the original into the streaming cache if needed, transcodes it with FFmpeg and serves the result with Range support; transcodes are cached on disk under _temp/transcoded so repeat requests are instant - GET api/mobile/stream/transcode/info reports FFmpeg availability so clients can warn the user and fall back to original downloads - Returns 501 when FFmpeg is missing; per-target locks avoid duplicate transcodes and a semaphore caps concurrent FFmpeg processes at 2 - MP3 keeps embedded cover art and tags; AAC (m4a) keeps tags * fix: reliable live task updates in Tasks Manager Task, download and upload tables required a full page reload to show progress because per-model event subscriptions were only wired when the component's static cached list was empty, so newly created models never got subscribed. Static lists were also shared between the Active and Queue table instances, and grid refreshes were fired from background threads without dispatcher marshaling. TransactionInfoService now owns all per-model subscriptions (hooked when a model enters any list, unhooked on remove/clear) and exposes a single aggregated TransactionsChanged event, throttled to 250ms with a guaranteed trailing raise. Tables use instance lists and subscribe only to that event, refreshing via InvokeAsync. The Tasks Manager header stats now update live as well. * feat: configurable parallel chunk transfers for faster downloads/uploads Transfers were capped at ~5-7 MB/s because WTelegramClient requests 512KB file parts with only 2 requests in flight (its default since v4.x), making throughput latency-bound at roughly 1MB per round-trip to Telegram's data center. Add a ParallelTransfers setting (default 4, range 1-16) applied to the main client and, before each document download, to the media-DC client that WTelegram resolves internally - secondary DC clients do not inherit the main client's setting, so it must be propagated per instance. The applied value is tracked per client and adjusted by delta, which stays correct even while parts are in flight. Changes take effect on the next transfer without restarting. * feat: multi-connection downloads to bypass per-connection speed limit Telegram enforces its throughput limit per MTProto connection (~5-6 MB/s), so pipelining more chunks on one connection cannot go faster; pushing harder only triggers FLOOD_PREMIUM_WAIT penalties. Official clients reach 50+ MB/s by opening several sessions to the file DC and splitting the file between them. Add an experimental multi-connection download mode (off by default): a per-DC pool of extra authorized clients, bootstrapped once from the main client via auth.exportAuthorization/importAuthorization, persisted as session files and reused across restarts. Files >=32MB are split in 4MB blocks served concurrently by 2-8 connections (configurable), each part written at its absolute offset via RandomAccess. Progress reports the contiguous completed prefix so persistence keeps a safe resume offset, while speed accounting counts every received part. Any failure falls back transparently to the standard sequential download. * fix: enable multi-connection mode on the file-manager download path Multi-connection downloads were only hooked into DownloadFile, but file-manager download tasks go through DownloadFileNow, which calls DownloadFileAndReturn with a FileStream target, so the feature never triggered on the most common path. Hook DownloadFileAndReturn (and the offset==0 branch of DownloadFileAndReturnWithOffset) when the destination is a FileStream, which supports the positional writes multi-connection mode requires. Memory and non-seekable targets keep the sequential path. * fix: bootstrap download pool via neighbor DC to avoid DC_ID_INVALID Telegram rejects auth.exportAuthorization towards the DC the caller is already connected to, so the pool bootstrap failed with DC_ID_INVALID whenever the file lived on the account home DC (the common case) and downloads always fell back to a single connection. Home the pool clients on a neighbor DC instead: exporting from the main client to the neighbor is always cross-DC, and from there the pool client can export towards any file DC, including the account home DC - both hops are cross-DC and accepted. This also makes the pool global rather than per-DC (one set of sessions serves every DC through per-file-DC transfer clients resolved with GetClientForDC), and the bootstrap failure log now includes the error message. * fix: finalize pool client login and drop probe RPCs after import The pool bootstrap verified the imported authorization with users.getUsers, which answers AUTH_KEY_UNREGISTERED on an imported session even though the import succeeded and file requests work, so the bootstrap always aborted and downloads fell back to a single connection. Import the exported authorization as the first call on the fresh client, finalize it client-side with LoginAlreadyDone (recording the UserId in the session), and make no verification RPC - workers verify by use and fall back on error. With the UserId recorded, WTelegram's GetClientForDC now handles the per-file-DC authorization automatically, replacing the manual transfer-client export/import logic; persisted sessions skip the import on later runs via the recorded UserId. * fix: tolerate re-import on an already-authorized pool session key Session files persisted by earlier runs (where the import succeeded but the login was never finalized client-side) hold a key that already carries the account authorization; re-importing onto it is rejected by the server with AUTH_BYTES_INVALID and the bootstrap aborted. Treat AUTH_BYTES_INVALID on import as already-authorized: finalize the login client-side with the user id returned by exportAuthorization and let the workers verify the session by use, falling back to the sequential download if it turns out to be broken. * feat: pool clients clone the main session instead of importing auth The exportAuthorization/importAuthorization bootstrap turned out to be a dead end: an imported session is a limited authorization - file requests work, but probe RPCs and re-exports answer AUTH_KEY_UNREGISTERED - so the pool client could never authorize its per-file-DC transfer connections (GetClientForDC's automatic export failed with AUTH_KEY_UNREGISTERED) and downloads always fell back. Clone the main session file instead: each pool client loads a copy of WTelegram.session, sharing the fully-authorized main auth key, while WTelegram assigns a fresh transient MTProto session id per client instance. The server sees extra connections of the existing authorization - the exact model official clients use for parallel downloads. Telegram's throughput limit is per connection/session, not per auth key, so each clone gets its own allowance. No authorizations are created, nothing appears in the device list, and cross-DC files keep working because the clones are fully logged sessions. * fix: clone the session despite the live file lock The main client keeps WTelegram.session open (often exclusively), so File.Copy failed with a sharing violation and the pool bootstrap always fell back to single-connection downloads. Snapshot the session file at client creation, before WTelegram opens and locks it, and make the clone routine try a share-friendly stream copy of the live file first, falling back to the startup snapshot. Session state staleness is harmless: the auth key never changes and server salts are renegotiated automatically. * feat: pipeline file parts within each download connection (#107) * feat: pipeline file parts within each download connection Workers requested their block's 1MB parts sequentially, paying a full round-trip of dead time per part and capping each connection around 3-4 MB/s regardless of its server-side allowance - the multi-connection download barely improved on a single connection (~10 MB/s with dips). Request all parts of a block concurrently on the block's connection, keeping each connection's pipe full (the same pipelining official clients use), and log a completion summary with the effective average speed to make future tuning measurable. Part writes stay positional and block completion still gates the contiguous confirmed prefix used for progress and resume persistence. * feat: make multi-connection tuning configurable with documented defaults Expose the remaining hardcoded transfer knobs in General Config: chunk size (snapped to Telegram's allowed 128/256/512/1024 KB values, 512 being WTelegramClient's own default), block size per connection (which determines the requests in flight per connection) and the minimum file size for multi-connection mode. Values are captured once per download so a config change cannot desynchronize offsets mid-transfer. The Config page now states the library default, app default and recommended value for each transfer setting, so the stock WTelegramClient behavior (2 parallel chunks, 512KB parts, single connection) can be restored by configuration alone. * feat: real sea-wave effect on the top bar download/upload buttons The water-fill buttons showed a flat colored block with a horizontal shine sweep - no actual wave at the waterline. Replace the shine with two repeating SVG wave crests that ride exactly on the fill level (the .water-wave element's top edge), drifting horizontally at different speeds and in opposite directions, overlapping the fill by 1px so no seam shows. The fill itself now uses a vertical gradient (deeper at the bottom, lighter at the surface) per variant color, wave motion is disabled under prefers-reduced-motion, and the stylesheet link gets a version query so cached browsers pick up the change. No markup changes to the buttons themselves. * feat: auth guard before rendering with return to the requested page After an app restart the Telegram client exists but the user is not loaded, so pages rendered first and only then (on first render) the layout noticed the missing user and hard-redirected to the login page, losing the URL the user was visiting; after authenticating, login always landed on /fetchdata. Resolve the session in the layouts' OnInitializedAsync, before any page content renders: the body is gated behind the check (page components are not instantiated until it completes), a silent session restore via checkAuth(null) is attempted first, and only when interactive login is really needed does the guard bounce to the login page, passing the requested URL as ?returnUrl. The login page navigates back to that URL (local paths only, to avoid open redirects) after a successful login. ConfigLayout gets the same guard; the old after-render check is removed. * feat: QR code login option in the web login page The QR login plumbing (CallQrGenerator wrapping LoginWithQRCode, QR rendering in Index) existed but nothing invoked it, and it could not have worked from the web anyway: when the account has 2FA, LoginWithQRCode asks for the password through Config("password"), which with the convenience constructor prompts on the console - QR login only worked when driving the library from a terminal. Wire it end to end: - The main client is now built with a custom config callback that routes the "password" request to the web UI: a QrPasswordNeeded event switches the login form to the 2FA password step and the value is handed back to the waiting login task, which blocks on a TaskCompletionSource (5 minute timeout) on its background thread. - The login page offers "Log in with QR code" next to the phone step: it shows the tg://login QR (auto-refreshed by the library when each token expires), instructions and a back button; on success the shared post-login initialization runs and navigation proceeds as with the normal flow. - DoLogin's post-login tail is extracted into CompleteLogin, reused by the QR flow. - checkAuth: when a session exists but no user data file is saved (the QR case - there is no phone to save), attempt a silent session restore via DoLogin(null) instead of always bouncing to the phone step, so QR sessions survive app restarts. * feat: live refresh in the download/upload/task info modals The info modals held a live reference to their model but only rendered a snapshot taken when opened, so progress, state, duration and speed froze until the modal was reopened. Subscribe each modal to the aggregated throttled TransactionsChanged event while it is visible (subscribed on ShowModal, unsubscribed on HideModal and Dispose) and re-render on the UI thread, following the same pattern the transfer tables use.
mateof
added a commit
that referenced
this pull request
Jul 22, 2026
* Develop to main (#90) * fix: fix folder creation logic to ensure CurrentFolder is valid before proceeding * fix: solve upload to empty folder and upload to root folder * fix: solve folder problem * Bump version to 3.6.3 * Develop to main (#112) * fix: fix folder creation logic to ensure CurrentFolder is valid before proceeding * fix: solve upload to empty folder and upload to root folder * fix: solve folder problem * Sync develop with main after v3.6.3 (#93) * Develop to main (#90) * fix: fix folder creation logic to ensure CurrentFolder is valid before proceeding * fix: solve upload to empty folder and upload to root folder * fix: solve folder problem * Bump version to 3.6.3 --------- Co-authored-by: Mateo <mateof@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: update MongoDB.Driver and System.IO.Hashing package versions * feat: wire progressive download cache into tfm streaming endpoint - StreamAudioByTfmId now starts the background ProgressiveDownloadService download (previously injected but never invoked) so every streamed track is fetched from Telegram once and persisted to the disk cache - Serve ranges from the growing cache file, waiting briefly when the background download is close instead of opening duplicate fetches - Direct Telegram fetches (far seeks) now stream 512KB chunks to the response via new DownloadFileStreamChunks and are limited by a semaphore - Robust Range parsing: TryParse, suffix ranges (bytes=-N), 416 for unsatisfiable ranges, removed ambiguous to==0 sentinel - ProgressiveDownloadService: fix IsRangeAvailable null check, drop stale entries when cache files are evicted, cap retries with backoff, and trim the cache directory to 10GB (oldest first, throttled) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: configurable STRM streaming mode with progressive disk cache Add a 'Streaming Mode' setting (Direct streaming / Progressive cache / Full preload) selectable in the web Config page, used when generating STRM files for Emby/Kodi. - New GetFileStreamCached endpoint: streams from Telegram with Range support while a background download fills the local cache; later ranges and replays are served from disk. - ProgressiveDownloadService now supports split (multi-message) files, caching parts sequentially into a single file with resume support. - Direct seeks ahead of the cache locate the Telegram part containing the requested range and cap the response at the part boundary. - STRM generation picks the endpoint from the configured mode; files smaller than MaxPreloadFileSizeInMb are still fully preloaded. - Backwards compatible with the legacy PreloadFilesOnStream flag (kept in sync on save; used as fallback when the new setting is unset). * fix: show progress and honor cancel for progressive cache downloads The background cache download appeared in the downloads list but never updated its progress and could not be stopped: - Report progress through DownloadModel.ProgressCallback (updates percentage, transmitted/size strings, global speed stats and fires the UI events) instead of writing _transmitted directly. The task is now also marked Completed when the download finishes. - Check the task state on every chunk so pressing Cancel (or Pause) in the downloads list actually stops the background download. - A user cancel is remembered for 1 hour per file so ongoing playback range requests don't immediately restart the cache download; the stream keeps working through direct Telegram fetches. A later playback caches again. - Start the progress counter at the resume offset so resumed downloads don't inflate the global speed stats. - Incomplete downloads no longer linger as 'Working' in the list. * feat: audio transcoding endpoint for offline downloads (MP3/AAC) - GET api/mobile/stream/tfm/{channelId}/{tfmId}/transcoded?format=mp3|aac&bitrate=N downloads the original into the streaming cache if needed, transcodes it with FFmpeg and serves the result with Range support; transcodes are cached on disk under _temp/transcoded so repeat requests are instant - GET api/mobile/stream/transcode/info reports FFmpeg availability so clients can warn the user and fall back to original downloads - Returns 501 when FFmpeg is missing; per-target locks avoid duplicate transcodes and a semaphore caps concurrent FFmpeg processes at 2 - MP3 keeps embedded cover art and tags; AAC (m4a) keeps tags * fix: reliable live task updates in Tasks Manager Task, download and upload tables required a full page reload to show progress because per-model event subscriptions were only wired when the component's static cached list was empty, so newly created models never got subscribed. Static lists were also shared between the Active and Queue table instances, and grid refreshes were fired from background threads without dispatcher marshaling. TransactionInfoService now owns all per-model subscriptions (hooked when a model enters any list, unhooked on remove/clear) and exposes a single aggregated TransactionsChanged event, throttled to 250ms with a guaranteed trailing raise. Tables use instance lists and subscribe only to that event, refreshing via InvokeAsync. The Tasks Manager header stats now update live as well. * feat: configurable parallel chunk transfers for faster downloads/uploads Transfers were capped at ~5-7 MB/s because WTelegramClient requests 512KB file parts with only 2 requests in flight (its default since v4.x), making throughput latency-bound at roughly 1MB per round-trip to Telegram's data center. Add a ParallelTransfers setting (default 4, range 1-16) applied to the main client and, before each document download, to the media-DC client that WTelegram resolves internally - secondary DC clients do not inherit the main client's setting, so it must be propagated per instance. The applied value is tracked per client and adjusted by delta, which stays correct even while parts are in flight. Changes take effect on the next transfer without restarting. * feat: multi-connection downloads to bypass per-connection speed limit Telegram enforces its throughput limit per MTProto connection (~5-6 MB/s), so pipelining more chunks on one connection cannot go faster; pushing harder only triggers FLOOD_PREMIUM_WAIT penalties. Official clients reach 50+ MB/s by opening several sessions to the file DC and splitting the file between them. Add an experimental multi-connection download mode (off by default): a per-DC pool of extra authorized clients, bootstrapped once from the main client via auth.exportAuthorization/importAuthorization, persisted as session files and reused across restarts. Files >=32MB are split in 4MB blocks served concurrently by 2-8 connections (configurable), each part written at its absolute offset via RandomAccess. Progress reports the contiguous completed prefix so persistence keeps a safe resume offset, while speed accounting counts every received part. Any failure falls back transparently to the standard sequential download. * fix: enable multi-connection mode on the file-manager download path Multi-connection downloads were only hooked into DownloadFile, but file-manager download tasks go through DownloadFileNow, which calls DownloadFileAndReturn with a FileStream target, so the feature never triggered on the most common path. Hook DownloadFileAndReturn (and the offset==0 branch of DownloadFileAndReturnWithOffset) when the destination is a FileStream, which supports the positional writes multi-connection mode requires. Memory and non-seekable targets keep the sequential path. * fix: bootstrap download pool via neighbor DC to avoid DC_ID_INVALID Telegram rejects auth.exportAuthorization towards the DC the caller is already connected to, so the pool bootstrap failed with DC_ID_INVALID whenever the file lived on the account home DC (the common case) and downloads always fell back to a single connection. Home the pool clients on a neighbor DC instead: exporting from the main client to the neighbor is always cross-DC, and from there the pool client can export towards any file DC, including the account home DC - both hops are cross-DC and accepted. This also makes the pool global rather than per-DC (one set of sessions serves every DC through per-file-DC transfer clients resolved with GetClientForDC), and the bootstrap failure log now includes the error message. * fix: finalize pool client login and drop probe RPCs after import The pool bootstrap verified the imported authorization with users.getUsers, which answers AUTH_KEY_UNREGISTERED on an imported session even though the import succeeded and file requests work, so the bootstrap always aborted and downloads fell back to a single connection. Import the exported authorization as the first call on the fresh client, finalize it client-side with LoginAlreadyDone (recording the UserId in the session), and make no verification RPC - workers verify by use and fall back on error. With the UserId recorded, WTelegram's GetClientForDC now handles the per-file-DC authorization automatically, replacing the manual transfer-client export/import logic; persisted sessions skip the import on later runs via the recorded UserId. * fix: tolerate re-import on an already-authorized pool session key Session files persisted by earlier runs (where the import succeeded but the login was never finalized client-side) hold a key that already carries the account authorization; re-importing onto it is rejected by the server with AUTH_BYTES_INVALID and the bootstrap aborted. Treat AUTH_BYTES_INVALID on import as already-authorized: finalize the login client-side with the user id returned by exportAuthorization and let the workers verify the session by use, falling back to the sequential download if it turns out to be broken. * feat: pool clients clone the main session instead of importing auth The exportAuthorization/importAuthorization bootstrap turned out to be a dead end: an imported session is a limited authorization - file requests work, but probe RPCs and re-exports answer AUTH_KEY_UNREGISTERED - so the pool client could never authorize its per-file-DC transfer connections (GetClientForDC's automatic export failed with AUTH_KEY_UNREGISTERED) and downloads always fell back. Clone the main session file instead: each pool client loads a copy of WTelegram.session, sharing the fully-authorized main auth key, while WTelegram assigns a fresh transient MTProto session id per client instance. The server sees extra connections of the existing authorization - the exact model official clients use for parallel downloads. Telegram's throughput limit is per connection/session, not per auth key, so each clone gets its own allowance. No authorizations are created, nothing appears in the device list, and cross-DC files keep working because the clones are fully logged sessions. * fix: clone the session despite the live file lock The main client keeps WTelegram.session open (often exclusively), so File.Copy failed with a sharing violation and the pool bootstrap always fell back to single-connection downloads. Snapshot the session file at client creation, before WTelegram opens and locks it, and make the clone routine try a share-friendly stream copy of the live file first, falling back to the startup snapshot. Session state staleness is harmless: the auth key never changes and server salts are renegotiated automatically. * feat: pipeline file parts within each download connection (#107) * feat: pipeline file parts within each download connection Workers requested their block's 1MB parts sequentially, paying a full round-trip of dead time per part and capping each connection around 3-4 MB/s regardless of its server-side allowance - the multi-connection download barely improved on a single connection (~10 MB/s with dips). Request all parts of a block concurrently on the block's connection, keeping each connection's pipe full (the same pipelining official clients use), and log a completion summary with the effective average speed to make future tuning measurable. Part writes stay positional and block completion still gates the contiguous confirmed prefix used for progress and resume persistence. * feat: make multi-connection tuning configurable with documented defaults Expose the remaining hardcoded transfer knobs in General Config: chunk size (snapped to Telegram's allowed 128/256/512/1024 KB values, 512 being WTelegramClient's own default), block size per connection (which determines the requests in flight per connection) and the minimum file size for multi-connection mode. Values are captured once per download so a config change cannot desynchronize offsets mid-transfer. The Config page now states the library default, app default and recommended value for each transfer setting, so the stock WTelegramClient behavior (2 parallel chunks, 512KB parts, single connection) can be restored by configuration alone. * feat: real sea-wave effect on the top bar download/upload buttons The water-fill buttons showed a flat colored block with a horizontal shine sweep - no actual wave at the waterline. Replace the shine with two repeating SVG wave crests that ride exactly on the fill level (the .water-wave element's top edge), drifting horizontally at different speeds and in opposite directions, overlapping the fill by 1px so no seam shows. The fill itself now uses a vertical gradient (deeper at the bottom, lighter at the surface) per variant color, wave motion is disabled under prefers-reduced-motion, and the stylesheet link gets a version query so cached browsers pick up the change. No markup changes to the buttons themselves. * feat: auth guard before rendering with return to the requested page After an app restart the Telegram client exists but the user is not loaded, so pages rendered first and only then (on first render) the layout noticed the missing user and hard-redirected to the login page, losing the URL the user was visiting; after authenticating, login always landed on /fetchdata. Resolve the session in the layouts' OnInitializedAsync, before any page content renders: the body is gated behind the check (page components are not instantiated until it completes), a silent session restore via checkAuth(null) is attempted first, and only when interactive login is really needed does the guard bounce to the login page, passing the requested URL as ?returnUrl. The login page navigates back to that URL (local paths only, to avoid open redirects) after a successful login. ConfigLayout gets the same guard; the old after-render check is removed. * feat: QR code login option in the web login page The QR login plumbing (CallQrGenerator wrapping LoginWithQRCode, QR rendering in Index) existed but nothing invoked it, and it could not have worked from the web anyway: when the account has 2FA, LoginWithQRCode asks for the password through Config("password"), which with the convenience constructor prompts on the console - QR login only worked when driving the library from a terminal. Wire it end to end: - The main client is now built with a custom config callback that routes the "password" request to the web UI: a QrPasswordNeeded event switches the login form to the 2FA password step and the value is handed back to the waiting login task, which blocks on a TaskCompletionSource (5 minute timeout) on its background thread. - The login page offers "Log in with QR code" next to the phone step: it shows the tg://login QR (auto-refreshed by the library when each token expires), instructions and a back button; on success the shared post-login initialization runs and navigation proceeds as with the normal flow. - DoLogin's post-login tail is extracted into CompleteLogin, reused by the QR flow. - checkAuth: when a session exists but no user data file is saved (the QR case - there is no phone to save), attempt a silent session restore via DoLogin(null) instead of always bouncing to the phone step, so QR sessions survive app restarts. * feat: live refresh in the download/upload/task info modals The info modals held a live reference to their model but only rendered a snapshot taken when opened, so progress, state, duration and speed froze until the modal was reopened. Subscribe each modal to the aggregated throttled TransactionsChanged event while it is visible (subscribed on ShowModal, unsubscribed on HideModal and Dispose) and re-render on the UI thread, following the same pattern the transfer tables use. * Bump version to 3.7.0 --------- Co-authored-by: Mateo <mateof@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.