feat: shared followers - #85
Conversation
There was a problem hiding this comment.
Key Issues
The code lacks proper error handling, with empty catch blocks and missing try-catch wrappers for async operations, risking unhandled errors and application crashes. Unsafe type assertions and null handling could lead to runtime errors if the response structure is unexpected. There is a logic error in data labeling, where Twitch data is incorrectly marked as Kick data, potentially causing data misinterpretation.
| try { | ||
| const kick = await this.commonUtils().getAssetFile(this.workerService(), "brands/kick.svg"); | ||
| this.platformIcons = { kick }; | ||
| } catch {} |
There was a problem hiding this comment.
🐛 Possible Bug
The empty catch block silently ignores any errors that occur while loading platform icons. This makes it difficult to diagnose issues if the icon fails to load. The error should be logged to help with debugging.
| } catch {} | |
| } catch (error) { this.logger.warn('Failed to load Kick platform icon', error); } |
| await this.loadStreamersFromCommon(); | ||
| await this.refreshStatuses(); |
There was a problem hiding this comment.
🐛 Possible Bug
The calls to loadStreamersFromCommon() and refreshStatuses() are not wrapped in try-catch blocks. If these async operations fail, they will result in unhandled promise rejections that could crash the application.
| await this.loadStreamersFromCommon(); | |
| await this.refreshStatuses(); | |
| try { | |
| await this.loadStreamersFromCommon(); | |
| await this.refreshStatuses(); | |
| } catch (error) { | |
| this.logger.error('Failed to initialize Kick streamers module', error); | |
| } |
| private async loadStreamersFromCommon(): Promise<void> { | ||
| try { | ||
| const res = await this.workerService().send("getCommon", { platform: "twitch", key: "kickStreamers" }); | ||
| const value = (res && (res as { value: unknown | null }).value) as unknown; |
There was a problem hiding this comment.
🐛 Possible Bug
The type assertion and null handling for the response from workerService().send() is unsafe. The code assumes the response will have a value property without proper validation. If res is null or doesn't match the expected structure, the type assertion could cause runtime errors.
| const value = (res && (res as { value: unknown | null }).value) as unknown; | |
| const value = res?.value ?? null; |
| await this.workerService().send("setCommon", { | ||
| platform: "kick", | ||
| key: COMMON_KEYS.kick.twitchStreamers, | ||
| value: twitchFollowList, | ||
| }); |
There was a problem hiding this comment.
🐛 Possible Bug
The code is storing Twitch follow list data but setting the platform as 'kick'. This appears to be a logic error as the data source is from Twitch but is being labeled as Kick data.
| await this.workerService().send("setCommon", { | |
| platform: "kick", | |
| key: COMMON_KEYS.kick.twitchStreamers, | |
| value: twitchFollowList, | |
| }); | |
| await this.workerService().send("setCommon", { | |
| platform: "twitch", | |
| key: COMMON_KEYS.kick.twitchStreamers, | |
| value: twitchFollowList, | |
| }); |
| headers: { Authorization: authorization }, | ||
| credentials: "include", | ||
| }); | ||
| if (!res.ok) break; |
There was a problem hiding this comment.
🐛 Possible Bug
The code breaks the loop on any non-OK response (!res.ok) without checking the specific error. This could mask important API errors like rate limiting or auth issues, leading to incomplete data collection.
| if (!res.ok) break; | |
| if (!res.ok) throw new Error(`API request failed with status ${res.status}`); |
There was a problem hiding this comment.
Key Issues
The PR review highlights critical issues including the failure to create necessary database indexes during version upgrades, leading to an invalid database state; unchecked access to potentially undefined properties causing runtime errors; and a performance regression due to sequential data fetching instead of concurrent requests.
Co-authored-by: callstackai[bot] <186726322+callstackai[bot]@users.noreply.github.com>
Co-authored-by: callstackai[bot] <186726322+callstackai[bot]@users.noreply.github.com>
|
There was a problem hiding this comment.
Pull request overview
This PR introduces a cross-platform follow sharing feature that allows users to synchronize and view their followed channels between Twitch and Kick platforms. The implementation includes a new common database for storing shared data, follow synchronization mechanisms for both platforms, and user-facing settings to control the feature.
Key Changes
- Implemented a common database infrastructure using IndexedDB to store shared data across platforms
- Added follow synchronization modules for both Twitch and Kick that periodically sync followed channels
- Introduced two new settings per platform: one to share follows to other platforms and another to show follows from other platforms
Reviewed changes
Copilot reviewed 36 out of 40 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/shared/worker/worker.types.ts | Added getCommonData and setCommonData worker API actions with corresponding payload/response types |
| src/types/shared/storage/common-database.types.ts | Defined CommonDatabaseData type structure for storing shared follows across platforms |
| src/types/platforms/twitch/twitch.settings.types.ts | Added shareFollowsToOtherPlatforms and showFollowsFromOtherPlatforms settings |
| src/types/platforms/twitch/twitch.api.types.ts | Added TwitchChannelNode and TwitchMultiChannelResponse types for GraphQL channel queries |
| src/types/platforms/twitch/twitch.utils.types.ts | Defined KickStreamerInfo and StreamerInfo types for cross-platform streamer data |
| src/types/platforms/kick/kick.settings.types.ts | Added shareFollowsToOtherPlatforms and showFollowsFromOtherPlatforms settings |
| src/types/platforms/kick/kick.api.types.ts | Enhanced type definitions with detailed interfaces for channel responses and follow data |
| src/types/platforms/kick/kick.utils.types.ts | Added imports and duplicate streamer info types |
| src/shared/worker/worker.background.ts | Integrated CommonService into the worker initialization and handler registry |
| src/shared/worker/handler.registry.ts | Registered getCommonData and setCommonData handlers |
| src/shared/worker/common/set-common-data.handler.ts | Implemented handler for setting common database data |
| src/shared/worker/common/get-common-data.handler.ts | Implemented handler for retrieving common database data |
| src/shared/worker/common/common.service.ts | Created service layer for common data operations |
| src/shared/worker/common/common.database.ts | Implemented IndexedDB wrapper for persistent common data storage |
| src/shared/worker/common/common-database.constants.ts | Defined default structure for common database |
| src/shared/utils/common.utils.ts | Added getCookie utility method for reading browser cookies |
| src/shared/settings/common.service.ts | Created CommonDataService for content scripts to interact with common data |
| src/shared/platform/platform.ts | Instantiated CommonDataService in base Platform class |
| src/shared/module/shared-follows/follow-syncer.ts | Created abstract base class for platform-specific follow synchronization |
| src/shared/module/module.ts | Added commonDataService accessor to base Module class |
| src/platforms/twitch/twitch.utils.ts | Added getUserFollowList method to extract followed channels from UI components |
| src/platforms/twitch/twitch.platform.ts | Integrated SharedFollowsModule and passed commonDataService to modules |
| src/platforms/twitch/twitch.module.ts | Updated constructor to accept and pass commonDataService |
| src/platforms/twitch/twitch.constants.ts | Set default values for new follow sharing settings |
| src/platforms/twitch/modules/shared-follows/twitch.follow-syncer.ts | Implemented Twitch-specific follow synchronization logic |
| src/platforms/twitch/modules/shared-follows/shared-follows.module.tsx | Created module to manage Twitch follow sync timer and settings |
| src/platforms/twitch/modules/settings/settings.module.tsx | Added UI definitions for new follow sharing settings |
| src/platforms/twitch/modules/kick-streamers/kick-streamers.module.tsx | Commented-out module for displaying Kick streamers on Twitch |
| src/platforms/twitch/modules/expose-follows/expose-follows.module.tsx | Commented-out alternative implementation for exposing follows |
| src/platforms/kick/modules/twitch-streams/twitch-streams.module.tsx | Commented-out module for displaying Twitch streams on Kick |
| src/platforms/kick/modules/shared-follows/shared-follows.module.tsx | Created module to manage Kick follow sync timer and settings |
| src/platforms/kick/modules/shared-follows/kick.follow-syncer.ts | Implemented Kick-specific follow synchronization using API calls |
| src/platforms/kick/modules/settings/settings.module.tsx | Added UI definitions for new follow sharing settings |
| src/platforms/kick/kick.platform.ts | Integrated SharedFollowsModule and passed commonDataService to modules |
| src/platforms/kick/kick.module.ts | Updated constructor to accept and pass commonDataService |
| src/platforms/kick/kick.constants.ts | Set default values for new follow sharing settings |
| public/assets/brands/twitch.svg | Added Twitch brand SVG icon |
| public/assets/brands/twitch.png | Added Twitch brand PNG icon |
| public/assets/brands/kick.svg | Added Kick brand SVG icon |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export type CommonDatabaseData = { | ||
| sharedFollows: { | ||
| twitch: string[]; | ||
| kick: string[]; | ||
| }; | ||
| }; |
There was a problem hiding this comment.
The CommonDatabaseData type only contains sharedFollows with twitch and kick platforms. This design is not easily extensible if more platforms need to be added in the future. Consider using a more flexible structure like Record<string, string[]> or documenting the plan for adding additional platforms.
| // @ts-ignore its okay here | ||
| // biome-ignore lint/complexity/noBannedTypes: it's okay here | ||
| export type GetCommonDataPayload = {}; |
There was a problem hiding this comment.
The ts-ignore and biome-ignore comments suggest that an empty object type is being used intentionally. However, using an empty object type {} is generally not recommended. Consider using Record<string, never> for a truly empty object, or simply omit the payload type if no payload is needed (similar to how the ping action is defined with payload?: never on line 105).
| type TwitchStreamerInfo = { | ||
| username: string; | ||
| isLive: boolean; | ||
| game: string | null; | ||
| avatar: string | null; | ||
| url: string; | ||
| viewerCount: number; | ||
| }; | ||
|
|
||
| type StreamerInfo = TwitchStreamerInfo & { platform: string }; |
There was a problem hiding this comment.
The type definitions TwitchStreamerInfo and StreamerInfo are defined here but appear to be unused in this file. These types duplicate the same types defined in twitch.utils.types.ts. Consider removing these duplicate type definitions and importing them from the appropriate file if needed.
| import KickModule from "$kick/kick.module.ts"; | ||
| import type { KickModuleConfig } from "$types/shared/module/module.types.ts"; | ||
|
|
There was a problem hiding this comment.
The imports at the top of this file (KickModule and KickModuleConfig) appear to be unused since the entire file is commented out. If this file is intended to remain commented out for future use, consider removing these imports or adding a comment explaining why they're present.
|
|
||
| private getAuthHeader(): string | undefined { | ||
| const token = this.commonUtils.getCookie("session_token"); | ||
| if (!token) return; |
There was a problem hiding this comment.
The authorization token is retrieved from cookies without any validation or error handling. If the session_token cookie is missing, undefined is returned and the sync silently fails. Consider logging a more informative message when the token is missing to help users understand why follow syncing isn't working.
| if (!token) return; | |
| if (!token) { | |
| this.logger.warn("Kick follow sync: 'session_token' cookie is missing; cannot fetch followed channels."); | |
| return; | |
| } |
|
|
||
| private async startSyncTimer() { | ||
| this.stopSyncTimer(); | ||
| this.syncFollowsTimer = setInterval(() => this.twitchFollowsSyncer.getFollows(), 10000); // 10 secs |
There was a problem hiding this comment.
The sync interval is set to 10 seconds (10000 ms), which seems quite frequent for syncing follow lists. This could cause unnecessary API calls and performance overhead. Consider using a longer interval (e.g., 2-5 minutes) similar to what's used in the Kick implementation (120000 ms = 2 minutes).
| if (!login) return null; | ||
| return String(login).toLowerCase(); | ||
| }; | ||
| const names = [...streams, ...offline].map(extractLogin).filter((v): v is string => typeof v === "string"); |
There was a problem hiding this comment.
The filter condition uses a type guard (v): v is string => typeof v === "string" but this is redundant since the map already calls String() and toLowerCase() on each login value. If a login value is null or undefined, it would be converted to the string "null" or "undefined" by the String() call. Consider checking for null/undefined before the String() conversion instead.
| const names = [...streams, ...offline].map(extractLogin).filter((v): v is string => typeof v === "string"); | |
| const names = [...streams, ...offline] | |
| .map(extractLogin) | |
| .filter((v): v is string => v !== null); |
| private async fetchFollowedRecursive(cursor: number, collected: Set<string>) { | ||
| const authorization = this.getAuthHeader(); | ||
| if (!authorization) return; | ||
|
|
||
| try { | ||
| const url = new URL("https://kick.com/api/v2/channels/followed"); | ||
| url.searchParams.set("cursor", String(cursor)); | ||
|
|
||
| const { data } = await this.http.request<FollowedChannelsResponse>(url.href, { | ||
| method: "GET", | ||
| headers: { Authorization: authorization }, | ||
| }); | ||
|
|
||
| (data.channels ?? []).forEach((channel) => { | ||
| const name = (channel.channel_slug || channel.user_username || "").toString().trim(); | ||
| if (name) { | ||
| collected.add(name.toLowerCase()); | ||
| } | ||
| }); | ||
|
|
||
| if (typeof data.nextCursor === "number") { | ||
| await this.fetchFollowedRecursive(data.nextCursor, collected); | ||
| } |
There was a problem hiding this comment.
The recursive fetching doesn't have a maximum depth limit or safeguard against infinite loops. If the API returns an unexpected cursor value or enters a cycle, this could lead to infinite recursion. Consider adding a maximum depth parameter or iteration counter to prevent potential stack overflow or excessive API calls.
| pinnedStreamersEnabled: true, | ||
| xayoWatchtimeEnabled: true, | ||
| shareFollowsToOtherPlatforms: false, | ||
| showFollowsFromOtherPlatforms: true, |
There was a problem hiding this comment.
The default value for showFollowsFromOtherPlatforms is set to true, which means users will automatically see follows from other platforms without explicitly opting in. This could be surprising behavior for users. Consider setting this to false by default to make it an opt-in feature, especially since shareFollowsToOtherPlatforms is defaulted to false.
| showFollowsFromOtherPlatforms: true, | |
| showFollowsFromOtherPlatforms: false, |
| realVideoTimeEnabled: true, | ||
| realVideoTimeFormat12h: false, | ||
| shareFollowsToOtherPlatforms: false, | ||
| showFollowsFromOtherPlatforms: true, |
There was a problem hiding this comment.
The default value for showFollowsFromOtherPlatforms is set to true, which means users will automatically see follows from other platforms without explicitly opting in. This could be surprising behavior for users. Consider setting this to false by default to make it an opt-in feature, especially since shareFollowsToOtherPlatforms is defaulted to false.
| showFollowsFromOtherPlatforms: true, | |
| showFollowsFromOtherPlatforms: false, |
…UI (#126) * Initial plan * Refactor: Rename common data to shared-storage for better clarity Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * feat: Add centralized follow sync with static interval Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * feat: Add streamer status manager with rate limiting to background Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * feat: Uncomment and enable cross-platform streamer UI modules Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * chore: Clean up code formatting and add documentation Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * fix: Fix indentation in streamer-status manager Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * fix: Remove follow-sync from background, run biome check Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * fix: Fix all remaining biome linting errors Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> * Bump preact in the npm_and_yarn group across 1 directory (#129) Bumps the npm_and_yarn group with 1 update in the / directory: [preact](https://github.com/preactjs/preact). Updates `preact` from 10.28.1 to 10.28.2 - [Release notes](https://github.com/preactjs/preact/releases) - [Commits](preactjs/preact@10.28.1...10.28.2) --- updated-dependencies: - dependency-name: preact dependency-version: 10.28.2 dependency-type: direct:production dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: update selector for channel section (#130) * bump version * fix: handle optional core and nested playerInstance in media player l… (#131) * fix: handle optional core and nested playerInstance in media player logic * fixes * fix seekTo * bump version * fix version --------- Co-authored-by: igorovh <xoxo@igor.ovh> * feat: add stream latency reducer for kick and twitch * Prototype of latency reducer, only for Kick * Prototype for Twitch * chore: lint * feat(twitch): add mockup latency tab for latency-related options * refactor(twitch): move stream latency display toggle to dedicated tab * feat(twitch): add kick-identical mockup latency reducer options to latency tab * feat(twitch): add latency reducer constants * feat(twitch): extend twitch media player instance types to include access to raw video element * feat(twitch): add stream latency reducer module, add core functionality with hard-coded values * fix(twitch): fix weird commit error * refactor(twitch): scrap first prototype for stream latency reduction by @Kaedriz * refactor(twitch): opt for a single playback rate value instead of min/max, migrate from using hard-coded values to settings values * feat(twitch): extend latency component to include playback rate * feat(twitch): add getMediaPlayerPlaybackRate twitch util * refactor(twitch): refactor stream latency reducer module to use playback rate twitch util + edit naming * chore: cleanup * feat: add playbackRate signal to stream latency module with video ratechange event listener * refactor(twitch): organize latency settings declarations * feat(twitch): re-add min/max playback rate settings, add min/max threshold settings * feat(twitch): add latency offset for rate updates to prevent rapid updates, implement min/max rate changes depending on min/max thresholds, prevent FFZ overrides when attempting to change rate * fix(twitch): fix twitch default settings * chore: remove accidentally-commited vscode settings.json * Fixes playback not limited to 2 digits * WIP fix for twitch latency reducer * feat(twitch): enhance fix for latency reducer * Some changes to make it working again * Formatting * Fix compatibility with FFZ * Final touches to twitch version * style: change ordering to be more logical * refactor: Separate Reducer logic to separate module * Revert "feat(twitch): enhance fix for latency reducer" This reverts commit d4112f3. * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * style: Fix incomplete comment * refactor: Apply suggestion from Gemini * style: formatting fixes * Apply Gemini suggestion Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * refactor: remove obsolete check * refactor: optimize settings calls for reducer * fix: add error logging * refactor: remove redundant code * fix: Prevent possible bug * style: fix typo * refactor: remove redundant code * style: formatting * refactor: extract part of latency getter to utils * refactor: temporary move these new feature to experimental to test them out * resovle conflitcs * bump version and rename settings name * update settings category * comment experimental category --------- Co-authored-by: jamie <hi@jamie.to> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: igorovh <xoxo@igor.ovh> * feat: update ci and husky (#135) * feat: update ci and husky * Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * update * change to matrix * fix: regenerate lockfile for cross-platform CI compatibility - Remove old lockfile and regenerate with bun 1.3.8 - Add .bun-version to pin bun version - Fixes frozen-lockfile errors in Ubuntu CI environment * update ci * fix * fixes * remove lockfile --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * chore: update release.yml (#136) * chore: update release.yml * chore: fix name * release: update docs (#139) * chore: update release.yml * chore: fix name * ci: add merge master to develop * docs: update docs * docs: fix docs * docs: update docs * ci: add new scripts * chore: update package.json * ci: fix yamls * update url * update scripts * update * chore: test update package.json (#140) * chore: update package.json * ci: fix yamls * update url * update scripts * update * ci: update templates (#141) * ci: fix ci (#143) * ci: update templates * fixes * chore: bump version to v5.1.26 * chore: update templates (#142) * chore: update package.json * ci: fix yamls * update url * update scripts * update * ci: update templates (#141) * ci: fix ci (#143) * ci: update templates * fixes * chore: bump version to v5.1.26 --------- Co-authored-by: Enhancer Bot <contact@enhancer.at> * docs: update bug report template * ci: remove hotfix and release ci publish * ci: fix pr title ci (#145) * fix(twitch): fix media player instance getter for direct players (#144) * fix(twitch): fix media player instance getter for direct players (popouts, etc.) * chore: fix linting * fix: fix comment --------- Co-authored-by: igor <37638480+igorovh@users.noreply.github.com> Co-authored-by: igorovh <xoxo@igor.ovh> * fix: stream reducer working in vod (#147) * fix: stream reducer working in vod * Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update src/platforms/twitch/modules/stream-latency-reducer/stream-latency-reducer.module.tsx --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * ci: add upload extension (#148) * ci: add upload extension * fix * ci: add release to allowed pr titles * ci: update to GITHUB_TOKEN * chore: bump version to v5.1.27 * release: 5.1.27 (#149) * ci: fix pr title ci (#145) * fix(twitch): fix media player instance getter for direct players (#144) * fix(twitch): fix media player instance getter for direct players (popouts, etc.) * chore: fix linting * fix: fix comment --------- Co-authored-by: igor <37638480+igorovh@users.noreply.github.com> Co-authored-by: igorovh <xoxo@igor.ovh> * fix: stream reducer working in vod (#147) * fix: stream reducer working in vod * Apply suggestions from code review Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update src/platforms/twitch/modules/stream-latency-reducer/stream-latency-reducer.module.tsx --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * ci: add upload extension (#148) * ci: add upload extension * fix * ci: add release to allowed pr titles * ci: update to GITHUB_TOKEN * chore: bump version to v5.1.27 --------- Co-authored-by: jamie <hi@jamie.to> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Enhancer Bot <contact@enhancer.at> * ci: fix publish pipeline * chore: update LICENSE badge * ci: add autofix-ci * ci: fix linting * chore: bump version * fix: publishing ci * ci: change retentio day when uploading artifact * ci: update env anme * ci: add opencode agent --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: igorovh <37638480+igorovh@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Maksymilian Podstawski <115575127+maksPodstawski@users.noreply.github.com> Co-authored-by: igorovh <xoxo@igor.ovh> Co-authored-by: Kaedriz <kaedriz@proton.me> Co-authored-by: jamie <hi@jamie.to> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Enhancer Bot <contact@enhancer.at>
❌ Invalid PR TitleYour current title does not follow the required semantic format. Example format: |
Description
Briefly explain what this PR does. Is it a bug fix, new feature, or a refactor?
Testing
Select all the environments you tested this PR with:
Please describe how you tested this change in the selected environments.
Related Issues
If this PR addresses an issue, link it here (e.g.,
Closes #123).✨
Description by Callstackai
This PR introduces a new feature that allows sharing followed channels across platforms, specifically between Twitch and Kick. It includes the implementation of follow synchronization and settings for enabling/disabling this feature.
Diagrams of code changes
sequenceDiagram participant User participant Platform participant SharedFollowsModule participant FollowSyncer participant CommonDataService participant WorkerService participant CommonDatabase User->>Platform: Enable follow sharing Platform->>SharedFollowsModule: Initialize module SharedFollowsModule->>FollowSyncer: Start sync timer loop Every few minutes FollowSyncer->>Platform: Get followed channels Platform-->>FollowSyncer: Return channel list FollowSyncer->>CommonDataService: Update shared follows CommonDataService->>WorkerService: Send update request WorkerService->>CommonDatabase: Store follows data CommonDatabase-->>WorkerService: Confirm storage WorkerService-->>CommonDataService: Return success end Note over Platform,CommonDatabase: Follows are now shared between platforms User->>Platform: View follows from other platform Platform->>CommonDataService: Request shared follows CommonDataService->>WorkerService: Get common data WorkerService->>CommonDatabase: Retrieve follows CommonDatabase-->>WorkerService: Return follows data WorkerService-->>CommonDataService: Return data CommonDataService-->>Platform: Return follows list Platform-->>User: Display combined followsFiles Changed