diff options
-rw-r--r-- | .github/workflows/ci.yml | 12 | ||||
-rw-r--r-- | .github/workflows/release.yml | 30 | ||||
-rw-r--r-- | .github/workflows/tests.yml | 4 | ||||
-rw-r--r-- | .github/workflows/update-oss-attribution.yml | 8 | ||||
-rw-r--r-- | .github/workflows/updateInvidous.yml | 6 | ||||
-rw-r--r-- | manifest/manifest.json | 2 | ||||
-rw-r--r-- | public/_locales/en/messages.json | 6 | ||||
-rw-r--r-- | public/_locales/ko/messages.json | 4 | ||||
-rw-r--r-- | public/content.css | 10 | ||||
-rw-r--r-- | src/config.ts | 2 | ||||
-rw-r--r-- | src/content.ts | 22 | ||||
-rw-r--r-- | src/js-components/previewBar.ts | 6 | ||||
-rw-r--r-- | src/options.ts | 4 | ||||
-rw-r--r-- | src/popup.ts | 11 | ||||
-rw-r--r-- | src/utils/exporter.ts | 4 | ||||
-rw-r--r-- | src/utils/licenseKey.ts | 10 | ||||
-rw-r--r-- | src/utils/pageUtils.ts | 3 | ||||
-rw-r--r-- | src/utils/warnings.ts | 4 |
18 files changed, 94 insertions, 54 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb5b9d0e..f4e5b6a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,8 @@ jobs: steps: # Initialization - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' - run: npm ci @@ -25,7 +25,7 @@ jobs: # Create Chrome artifacts - name: Create Chrome artifacts run: npm run build:chrome - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: ChromeExtension path: dist @@ -37,7 +37,7 @@ jobs: # Create Firefox artifacts - name: Create Firefox artifacts run: npm run build:firefox - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: FirefoxExtension path: dist @@ -48,7 +48,7 @@ jobs: # Create Beta artifacts (Builds with the name changed to beta) - name: Create Chrome Beta artifacts run: npm run build:chrome -- --env stream=beta - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: ChromeExtensionBeta path: dist @@ -58,7 +58,7 @@ jobs: - name: Create Firefox Beta artifacts run: npm run build:firefox -- --env stream=beta - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: FirefoxExtensionBeta path: dist diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 943d54f5..9c8c0953 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,8 +12,8 @@ jobs: steps: # Initialization - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' - run: npm ci @@ -23,7 +23,7 @@ jobs: # Create Chrome artifacts - name: Create Chrome artifacts run: npm run build:chrome - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: ChromeExtension path: dist @@ -34,7 +34,7 @@ jobs: # Create Firefox artifacts - name: Create Firefox artifacts run: npm run build:firefox - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: FirefoxExtension path: dist @@ -44,7 +44,7 @@ jobs: # Create Beta artifacts (Builds with the name changed to beta) - name: Create Chrome Beta artifacts run: npm run build:chrome -- --env stream=beta - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: ChromeExtensionBeta path: dist @@ -55,7 +55,7 @@ jobs: # Create Safari artifacts - name: Create Safari artifacts run: npm run build:safari - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: SafariExtension path: dist @@ -66,7 +66,7 @@ jobs: run: rm -rf ./dist - name: Create Edge artifacts run: npm run build:edge - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: EdgeExtension path: dist @@ -75,35 +75,35 @@ jobs: # Upload each release asset - name: Upload ChromeExtension to release - uses: Shopify/upload-to-release@master + uses: Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467 with: args: builds/ChromeExtension.zip name: ChromeExtension.zip path: ./builds/ChromeExtension.zip repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Upload ChromeExtensionBeta to release - uses: Shopify/upload-to-release@master + uses: Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467 with: args: builds/ChromeExtensionBeta.zip name: ChromeExtensionBeta.zip path: ./builds/ChromeExtensionBeta.zip repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Upload FirefoxExtension to release - uses: Shopify/upload-to-release@master + uses: Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467 with: args: builds/FirefoxExtension.zip name: FirefoxExtension.zip path: ./builds/FirefoxExtension.zip repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Upload SafariExtension to release - uses: Shopify/upload-to-release@master + uses: Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467 with: args: builds/SafariExtension.zip name: SafariExtension.zip path: ./builds/SafariExtension.zip repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Upload EdgeExtension to release - uses: Shopify/upload-to-release@master + uses: Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467 with: args: builds/EdgeExtension.zip name: EdgeExtension.zip @@ -113,7 +113,7 @@ jobs: # Firefox Beta - name: Create Firefox Beta artifacts run: npm run build:firefox -- --env stream=beta - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: FirefoxExtensionBeta path: dist @@ -130,13 +130,13 @@ jobs: run: sudo apt-get install rename - name: Rename signed file run: cd ./web-ext-artifacts ; rename 's/.*/FirefoxSignedInstaller.xpi/' * - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: FirefoxExtensionSigned.xpi path: ./web-ext-artifacts/FirefoxSignedInstaller.xpi - name: Upload FirefoxSignedInstaller.xpi to release - uses: Shopify/upload-to-release@master + uses: Shopify/upload-to-release@07611424e04f1475ddf550e1c0dd650b867d5467 with: args: web-ext-artifacts/FirefoxSignedInstaller.xpi name: FirefoxSignedInstaller.xpi diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b14925ec..48c05848 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,8 +9,8 @@ jobs: steps: # Initialization - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' - run: npm ci diff --git a/.github/workflows/update-oss-attribution.yml b/.github/workflows/update-oss-attribution.yml index f8f684ba..6e64b859 100644 --- a/.github/workflows/update-oss-attribution.yml +++ b/.github/workflows/update-oss-attribution.yml @@ -12,9 +12,8 @@ jobs: update-oss: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '18' - name: Install and generate attribution @@ -25,7 +24,8 @@ jobs: mv ./oss-attribution/attribution.txt ./public/oss-attribution/attribution.txt - name: Create pull request to update list - uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 + uses: peter-evans/create-pull-request@b4d51739f96fca8047ad065eccef63442d8e99f7 + # v4.2.0 with: commit-message: Update OSS Attribution author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/.github/workflows/updateInvidous.yml b/.github/workflows/updateInvidous.yml index ede1b9b0..5c4baa89 100644 --- a/.github/workflows/updateInvidous.yml +++ b/.github/workflows/updateInvidous.yml @@ -8,8 +8,7 @@ jobs: check-list: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Download instance list run: | wget https://api.invidious.io/instances.json -O ci/data.json @@ -19,7 +18,8 @@ jobs: run: npm run ci:invidious - name: Create pull request to update list - uses: peter-evans/create-pull-request@923ad837f191474af6b1721408744feb989a4c27 + uses: peter-evans/create-pull-request@b4d51739f96fca8047ad065eccef63442d8e99f7 + # v4.2.0 with: commit-message: Update Invidious List author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/manifest/manifest.json b/manifest/manifest.json index 2292923c..c7a0e5d2 100644 --- a/manifest/manifest.json +++ b/manifest/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_fullName__", "short_name": "SponsorBlock", - "version": "5.1.0", + "version": "5.1.4", "default_locale": "en", "description": "__MSG_Description__", "homepage_url": "https://sponsor.ajay.app", diff --git a/public/_locales/en/messages.json b/public/_locales/en/messages.json index b3b9e152..7a5dd69b 100644 --- a/public/_locales/en/messages.json +++ b/public/_locales/en/messages.json @@ -116,6 +116,9 @@ "connectionError": { "message": "A connection error has occurred. Error code: " }, + "segmentsStillLoading": { + "message": "Segments still loading..." + }, "clearTimes": { "message": "Clear Segments" }, @@ -1243,5 +1246,8 @@ }, "exportSegmentsAsURL": { "message": "Share as URL" + }, + "segmentFetchFailureWarning": { + "message": "Warning: The server hasn't responded with segments yet. There might actually be segments on this video already submitted but you just haven't recieved them due to issues with the server." } } diff --git a/public/_locales/ko/messages.json b/public/_locales/ko/messages.json index e3c04ece..c5178ac3 100644 --- a/public/_locales/ko/messages.json +++ b/public/_locales/ko/messages.json @@ -392,7 +392,7 @@ "message": "건너뛰기로 제외된 시간 표시" }, "showTimeWithSkipsDescription": { - "message": "탐색 바 아래에 있는 동영상 시간 옆 괄호에 시간이 표시돼요. 건너뛸 구간을 제외할 실제로 재생하게 될 동영상의 길이를 보여줘요. \"탐색 바에 표시\"로만 지정된 구간도 포함해요." + "message": "이 시간은 탐색 바 아래에 있고 현재 시간 옆에 있는 대괄호로 표시돼요. 건너뛸 구간을 제외할 실제로 재생하게 될 동영상의 길이를 보여줘요. \"탐색 바에 표시\"로만 지정된 구간도 포함해요." }, "youHaveSkipped": { "message": "건너뛴 구간: " @@ -424,7 +424,7 @@ "message": "비공개 사용자 ID 가져오기/내보내기" }, "whatChangeUserID": { - "message": "이 정보를 다른 분께 공개하지 마세요. 비밀번호처럼 알려주면 위험한 정보랍니다. 다른 분이 이 정보를 가지고 나를 사칭할 수도 있어요. 공개 사용자 ID를 찾고 있다면, 팝업 내 클립보드 아이콘을 눌러주세요." + "message": "이 정보를 다른 분께 공개하지 마세요. 이건 비밀번호와 같으며 누구와도 공유해서는 안 되는 정보랍니다. 다른 분이 이 정보를 습득한다면, 나를 사칭할 수도 있어요. 공개 사용자 ID를 찾고 있다면, 팝업 내 클립보드 아이콘을 눌러주세요." }, "setUserID": { "message": "비공개 사용자 ID 설정" diff --git a/public/content.css b/public/content.css index 9f37ab7c..eb72e5cf 100644 --- a/public/content.css +++ b/public/content.css @@ -66,6 +66,11 @@ div:hover > #previewbar.sbNotInvidious { transform: translateY(-1em) !important; } +/* Pull up for precise seeking */ +.ytp-tooltip.sponsorCategoryTooltipVisible .ytp-tooltip-edu { + transform: translateY(-1em) !important; +} + .ytp-tooltip.sponsorCategoryTooltipVisible.sponsorTwoTooltips { transform: translateY(-2em) !important; } @@ -86,6 +91,11 @@ div:hover > #previewbar.sbNotInvidious { transform: translateY(2em) !important; } +/* Pull up for precise seeking */ +.ytp-tooltip.sponsorCategoryTooltipVisible.sponsorTwoTooltips .ytp-tooltip-edu { + transform: translateY(-2em) !important; +} + .ytp-big-mode .ytp-tooltip.sponsorCategoryTooltipVisible > .ytp-tooltip-text-wrapper { transform: translateY(0.5em) !important; } diff --git a/src/config.ts b/src/config.ts index 8d5ad5a0..ba3caf85 100644 --- a/src/config.ts +++ b/src/config.ts @@ -68,6 +68,7 @@ interface SBConfig { showCategoryWithoutPermission: boolean; showSegmentNameInChapterBar: boolean; useVirtualTime: boolean; + showSegmentFailedToFetchWarning: boolean; // Used to cache calculated text color info categoryPillColors: { @@ -202,6 +203,7 @@ const Config: SBObject = { showCategoryWithoutPermission: false, showSegmentNameInChapterBar: true, useVirtualTime: true, + showSegmentFailedToFetchWarning: true, categoryPillColors: {}, diff --git a/src/content.ts b/src/content.ts index 761307a1..6b87ddd9 100644 --- a/src/content.ts +++ b/src/content.ts @@ -56,6 +56,7 @@ let sponsorVideoID: VideoID = null; const skipNotices: SkipNotice[] = []; let activeSkipKeybindElement: ToggleSkippable = null; let retryFetchTimeout: NodeJS.Timeout = null; +let shownSegmentFailedToFetchWarning = false; // JSON video info let videoInfo: VideoInfo = null; @@ -271,8 +272,13 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo for (const segment of importedSegments) { if (!sponsorTimesSubmitting.some( (s) => Math.abs(s.segment[0] - segment.segment[0]) < 1 - && Math.abs(s.segment[1] - segment.segment[1]) < 1) - && (segment.category !== "chapter" || utils.getCategorySelection("chapter"))) { + && Math.abs(s.segment[1] - segment.segment[1]) < 1)) { + if (segment.category === "chapter" && !utils.getCategorySelection("chapter")) { + segment.category = "chooseACategory" as Category; + segment.actionType = ActionType.Skip; + segment.description = ""; + } + sponsorTimesSubmitting.push(segment); addedSegments = true; } @@ -284,6 +290,7 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo updateEditButtonsOnPlayer(); updateSponsorTimesSubmitting(false); + submitSponsorTimes(); } sendResponse({ @@ -338,6 +345,8 @@ function resetValues() { sponsorTimes = []; existingChaptersImported = false; sponsorSkipped = []; + lastResponseStatus = 0; + shownSegmentFailedToFetchWarning = false; sponsorVideoID = null; videoInfo = null; @@ -716,7 +725,7 @@ function getVirtualTime(): number { const virtualTime = lastTimeFromWaitingEvent ?? (lastKnownVideoTime.videoTime ? (performance.now() - lastKnownVideoTime.preciseTime) * video.playbackRate / 1000 + lastKnownVideoTime.videoTime : null); - if (Config.config.useVirtualTime && !isSafari() && virtualTime + if (Config.config.useVirtualTime && !utils.isFirefox() && !isSafari() && virtualTime && Math.abs(virtualTime - video.currentTime) < 0.6 && video.currentTime !== 0) { return virtualTime; } else { @@ -1921,6 +1930,13 @@ function startOrEndTimingNewSegment() { updateSponsorTimesSubmitting(false); importExistingChapters(false); + + if (lastResponseStatus !== 200 && lastResponseStatus !== 404 + && !shownSegmentFailedToFetchWarning && Config.config.showSegmentFailedToFetchWarning) { + alert(chrome.i18n.getMessage("segmentFetchFailureWarning")); + + shownSegmentFailedToFetchWarning = true; + } } function getIncompleteSegment(): SponsorTime { diff --git a/src/js-components/previewBar.ts b/src/js-components/previewBar.ts index 84ebb155..c9ece9e7 100644 --- a/src/js-components/previewBar.ts +++ b/src/js-components/previewBar.ts @@ -676,7 +676,7 @@ class PreviewBar { for (let i = 0; i < sections.length; i++) { const section = sections[i] as HTMLElement; const checkElement = section.querySelector(selector) as HTMLElement; - const currentSectionWidthNoMargin = this.getPartialChapterSectionStyle(section, "width") || progressBar.clientWidth; + const currentSectionWidthNoMargin = this.getPartialChapterSectionStyle(section, "width") ?? progressBar.clientWidth; const currentSectionWidth = currentSectionWidthNoMargin + this.getPartialChapterSectionStyle(section, "marginRight"); @@ -728,8 +728,8 @@ class PreviewBar { private getPartialChapterSectionStyle(element: HTMLElement, param: string): number { const data = element.style[param]; - if (data?.includes("100%")) { - return 0; + if (data?.includes("%")) { + return this.customChaptersBar.clientWidth * (parseFloat(data.replace("%", "")) / 100); } else { return parseInt(element.style[param].match(/\d+/g)?.[0]) || 0; } diff --git a/src/options.ts b/src/options.ts index 888e7aaf..e963a683 100644 --- a/src/options.ts +++ b/src/options.ts @@ -532,7 +532,7 @@ function activatePrivateTextChange(element: HTMLElement) { case "userID": if (Config.config[option]) { utils.asyncRequestToServer("GET", "/api/userInfo", { - userID: Config.config[option], + publicUserID: utils.getHash(Config.config[option]), values: ["warnings", "banned"] }).then((result) => { const userInfo = JSON.parse(result.responseText); @@ -672,4 +672,4 @@ function copyDebugOutputToClipboard() { function isIncognitoAllowed(): Promise<boolean> { return new Promise((resolve) => chrome.extension.isAllowedIncognitoAccess(resolve)); -}
\ No newline at end of file +} diff --git a/src/popup.ts b/src/popup.ts index ede826e2..d24721b0 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -281,7 +281,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { if (!Config.config.payments.freeAccess && !noRefreshFetchingChaptersAllowed()) values.push("freeChaptersAccess"); utils.asyncRequestToServer("GET", "/api/userInfo", { - userID: Config.config.userID, + publicUserID: await utils.getHash(Config.config.userID), values }).then((res) => { if (res.status === 200) { @@ -456,8 +456,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { PageElements.videoFound.innerHTML = chrome.i18n.getMessage("sponsor404"); PageElements.issueReporterImportExport.classList.remove("hidden"); } else { - PageElements.videoFound.innerHTML = chrome.i18n.getMessage("connectionError") + request.status; - PageElements.issueReporterImportExport.classList.add("hidden"); + if (request.status) { + PageElements.videoFound.innerHTML = chrome.i18n.getMessage("connectionError") + request.status; + } else { + PageElements.videoFound.innerHTML = chrome.i18n.getMessage("segmentsStillLoading"); + } + + PageElements.issueReporterImportExport.classList.remove("hidden"); } } diff --git a/src/utils/exporter.ts b/src/utils/exporter.ts index 16b970f3..8c765a34 100644 --- a/src/utils/exporter.ts +++ b/src/utils/exporter.ts @@ -8,7 +8,7 @@ const inTest = typeof chrome === "undefined"; const chapterNames = CompileConfig.categoryList.filter((code) => code !== "chapter") .map((code) => ({ code, - name: !inTest ? chrome.i18n.getMessage("category_" + code) : code + names: !inTest ? [chrome.i18n.getMessage("category_" + code), shortCategoryName(code)] : [code] })); export function exportTimes(segments: SponsorTime[]): string { @@ -47,7 +47,7 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[] const title = titleLeft?.length > titleRight?.length ? titleLeft : titleRight; if (title) { - const determinedCategory = chapterNames.find(c => c.name === title)?.code as Category; + const determinedCategory = chapterNames.find(c => c.names.includes(title))?.code as Category; const segment: SponsorTime = { segment: [startTime, GenericUtils.getFormattedTimeToSeconds(match[1])], diff --git a/src/utils/licenseKey.ts b/src/utils/licenseKey.ts index 7ce41a8a..77eca21d 100644 --- a/src/utils/licenseKey.ts +++ b/src/utils/licenseKey.ts @@ -15,7 +15,7 @@ export async function checkLicenseKey(licenseKey: string): Promise<boolean> { Config.config.showChapterInfoMessage = false; Config.config.payments.lastCheck = Date.now(); Config.forceSyncUpdate("payments"); - + return true; } } catch (e) { } //eslint-disable-line no-empty @@ -43,7 +43,7 @@ export async function fetchingChaptersAllowed(): Promise<boolean> { return licensePromise; } } - + if (Config.config.payments.chaptersAllowed) return true; if (Config.config.payments.lastCheck === 0 && Date.now() - Config.config.payments.lastFreeCheck > 2 * 24 * 60 * 60 * 1000) { @@ -53,7 +53,7 @@ export async function fetchingChaptersAllowed(): Promise<boolean> { // Check for free access if no license key, and it is the first time const result = await utils.asyncRequestToServer("GET", "/api/userInfo", { value: "freeChaptersAccess", - userID: Config.config.userID + publicUserID: await utils.getHash(Config.config.userID) }); try { @@ -66,7 +66,7 @@ export async function fetchingChaptersAllowed(): Promise<boolean> { Config.config.payments.chaptersAllowed = true; Config.config.showChapterInfoMessage = false; Config.forceSyncUpdate("payments"); - + return true; } } @@ -74,4 +74,4 @@ export async function fetchingChaptersAllowed(): Promise<boolean> { } return false; -}
\ No newline at end of file +} diff --git a/src/utils/pageUtils.ts b/src/utils/pageUtils.ts index db18aae7..94c58bfc 100644 --- a/src/utils/pageUtils.ts +++ b/src/utils/pageUtils.ts @@ -71,7 +71,8 @@ export function getExistingChapters(currentVideoID: VideoID, duration: number): const chapters: SponsorTime[] = []; // .ytp-timed-markers-container indicates that key-moments are present, which should not be divided - if (chaptersBox && !(document.querySelector(".ytp-timed-markers-container")?.childElementCount > 0)) { + if (chaptersBox && !(getControls()?.parentElement?.parentElement + ?.querySelector(".ytp-timed-markers-container")?.childElementCount > 0)) { let lastSegment: SponsorTime = null; const links = chaptersBox.querySelectorAll("ytd-macro-markers-list-item-renderer > a"); for (const link of links) { diff --git a/src/utils/warnings.ts b/src/utils/warnings.ts index f2f2657e..17e919ba 100644 --- a/src/utils/warnings.ts +++ b/src/utils/warnings.ts @@ -13,7 +13,7 @@ export interface ChatConfig { export async function openWarningDialog(contentContainer: ContentContainer): Promise<void> { const userInfo = await utils.asyncRequestToServer("GET", "/api/userInfo", { - userID: Config.config.userID, + publicUserID: await utils.getHash(Config.config.userID), values: ["warningReason"] }); @@ -63,4 +63,4 @@ export async function openWarningDialog(contentContainer: ContentContainer): Pro export function openChat(config: ChatConfig): void { window.open("https://chat.sponsor.ajay.app/#" + GenericUtils.objectToURI("", config, false)); -}
\ No newline at end of file +} |