diff --git a/.github/workflows/Check_patch_notes.yml b/.github/workflows/Check_patch_notes.yml new file mode 100644 index 00000000..45084979 --- /dev/null +++ b/.github/workflows/Check_patch_notes.yml @@ -0,0 +1,24 @@ +name: Check patch notes + +on: + pull_request: + branches: + - in-dev + workflow_dispatch: + +jobs: + check_patch_notes: + runs-on: ubuntu-latest # windows-latest | macos-latest + name: Test changed-files + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 2 # "0" OR "2" -> To retrieve the preceding commit. + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v9.2 + + - name: Run when patch noted don't change + if: ${{ !contains(steps.changed-files.outputs.modified_files, 'patch_notes.txt') }} + run: exit 1 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41ee6aaa..1d96baf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,12 @@ -name: Build +name: Build dev version on: push: branches: - - 'master' + - 'in-dev' pull_request: + branches: + - 'in-dev' workflow_dispatch: env: @@ -193,8 +195,8 @@ jobs: path: Twitch.Drops.Miner.Linux.AppImage.zip update_releases_page: + #NOTEif: github.event.pull_request.merged == true || github.event_name == 'push' name: Upload builds to Releases - if: github.event_name != 'pull_request' needs: - windows - linux-pyinstaller @@ -221,7 +223,10 @@ jobs: artifactErrorsFailBuild: true artifacts: artifacts/*/* body: | - **This is an automatically generated in-development pre-release version of the application, that includes the latest master branch changes.** + # ⚠️ Please help with translation as tracked in #2 ! + + *** + **This is an automatically generated in-development pre-release version of the application, that includes the latest in-dev branch changes.** **⚠️ This build is not stable and may end up terminating with a fatal error. ⚠️** **Use at your own risk.** diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..98e7be4f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,257 @@ +name: Build release + +on: + pull_request: + types: [closed] + branches: + - 'master' + workflow_dispatch: + +env: + PYTHON_VERSION: '3.10' + +jobs: + windows: + name: Windows + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up variables + id: vars + run: | + Add-Content $env:GITHUB_OUTPUT "sha_short=$(git rev-parse --short HEAD)" + + - name: Append git revision to project version + run: | + (Get-Content version.py) ` + -Replace '^__version__\s*=\s*"[^"]+', "`$0.${{steps.vars.outputs.sha_short}}" |` + Out-File version.py + + # Ensure Python version + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{env.PYTHON_VERSION}} + + - name: Install project dependencies + run: | + python3 -m pip install wheel + python3 -m pip install -r requirements.txt + + - name: Install UPX + run: | + Invoke-WebRequest -Uri https://github.com/upx/upx/releases/download/v4.0.2/upx-4.0.2-win64.zip -OutFile (Join-Path $env:Temp upx.zip) + Expand-Archive -LiteralPath (Join-Path $env:Temp upx.zip) -DestinationPath $env:Temp + Move-Item -Path (Join-Path $env:Temp upx-*) -Destination (Join-Path $env:Temp upx) + Add-Content $env:GITHUB_PATH (Join-Path $env:Temp upx) + + - name: Install PyInstaller + run: | + python3 -m pip install pyinstaller + + - name: Create portable executable + run: | + pyinstaller build.spec + + - name: Create release folder + run: | + $FolderName = 'Twitch Drops Miner' + New-Item $FolderName -ItemType Directory + Copy-Item dist\*.exe $FolderName + Copy-Item manual.txt $FolderName + Compress-Archive -Path $FolderName -DestinationPath Twitch.Drops.Miner.Windows.zip + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + name: Twitch.Drops.Miner.Windows + path: Twitch.Drops.Miner.Windows.zip + + linux-pyinstaller: + name: Linux (PyInstaller) + runs-on: ubuntu-20.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up variables + id: vars + run: | + echo "sha_short=$(git rev-parse --short HEAD)" >> "${GITHUB_OUTPUT}" + + - name: Append git revision to project version + run: | + sed -ri "s/^__version__\s*=\s*\"[^\"]+/\0.${{ steps.vars.outputs.sha_short }}/" version.py + + # NOTE: We're only use a custom version of Python here because truststore requires at least Python 3.10, but Ubuntu 20.04 has Python 3.8. + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: ${{env.PYTHON_VERSION}} + + - name: Install system dependencies + run: | + sudo apt update + sudo apt install gir1.2-appindicator3-0.1 libgirepository1.0-dev python3-tk + + - name: Install project dependencies + run: | + python3 -m pip install wheel + python3 -m pip install -r requirements.txt + + - name: Install PyInstaller + run: | + python3 -m pip install pyinstaller + + # NOTE: Remove this step if/once libxft gets updated to 2.3.5 or newer on Ubuntu 20.04, which currently has 2.3.3. + - name: Build a recent version of libXft + run: | + mkdir -p /tmp/libXft + cd /tmp/libXft + curl -L https://xorg.freedesktop.org/releases/individual/lib/libXft-2.3.8.tar.xz -o libXft.tar.xz + tar xvf libXft.tar.xz + cd libXft-* + ./configure --prefix=/tmp/libXft --sysconfdir=/etc --disable-static + make + make install-strip + + - name: Create portable executable + run: | + LD_LIBRARY_PATH=/tmp/libXft/lib xvfb-run --auto-servernum pyinstaller build.spec + + - name: Show PyInstaller warnings + run: | + cat build/build/warn-build.txt || true + + - name: Create release folder + run: | + folder='Twitch Drops Miner' + mkdir "${folder}" + cp manual.txt dist/* "${folder}" + 7z a Twitch.Drops.Miner.Linux.PyInstaller.zip "${folder}" + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + name: Twitch.Drops.Miner.Linux.PyInstaller + path: Twitch.Drops.Miner.Linux.PyInstaller.zip + + linux-appimage: + name: Linux (AppImage) + runs-on: ubuntu-22.04 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up variables + id: vars + run: | + echo "app_version=$(python3 -c 'from version import __version__ as v; print(v)')" >> "${GITHUB_OUTPUT}" + echo "sha_short=$(git rev-parse --short HEAD)" >> "${GITHUB_OUTPUT}" + + - name: Append git revision to project version + run: | + sed -ri "s/^__version__\s*=\s*\"[^\"]+/\0.${{steps.vars.outputs.sha_short}}/" version.py + + - name: Install system dependencies + run: | + sudo apt update + sudo apt install libgirepository1.0-dev python3-testresources + + - name: Download AppImage Builder + run: | + curl -L https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage -o appimage-builder + chmod +x appimage-builder + + - name: Create AppImage + env: + APPIMAGE_EXTRACT_AND_RUN: 1 + APP_VERSION: ${{steps.vars.outputs.app_version}}.${{steps.vars.outputs.sha_short}} + PYTHON_VERSION: ${{env.PYTHON_VERSION}} + run: | + ./appimage-builder --recipe appimage/AppImageBuilder.yml + + - name: Create release folder + run: | + folder='Twitch Drops Miner' + mkdir "${folder}" + cp *.AppImage manual.txt "${folder}" + 7z a Twitch.Drops.Miner.Linux.AppImage.zip "${folder}" + + - name: Upload build artifact + uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + name: Twitch.Drops.Miner.Linux.AppImage + path: Twitch.Drops.Miner.Linux.AppImage.zip + + update_releases_page: + name: Upload builds to Releases + #NOTEif: github.event.pull_request.merged == true + needs: + - windows + - linux-pyinstaller + - linux-appimage + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Get next version + uses: reecetech/version-increment@2024.4.3 + id: version + with: + scheme: semver + increment: minor + + - name: Set up variables + id: vars + run: | + echo "date_now=$(date --rfc-3339=seconds)" >> "${GITHUB_OUTPUT}" + echo "sha_short=$(git rev-parse --short HEAD)" >> "${GITHUB_OUTPUT}" + + - name: Download build artifacts from previous jobs + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Read patch notes from file + id: patch_notes + uses: juliangruber/read-file-action@v1.1.7 + with: + path: ./patch_notes.txt + + - name: Upload builds to Releases + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifactErrorsFailBuild: true + artifacts: artifacts/*/* + body: | + # ⚠️ Please help with translation as tracked in #2 and channel points as tracked in #23 ! + + *** + **This is an automatically generated updated version of the application, that includes the latest master branch changes.** + **This build should be stable, but if you encounter anything, please report any issues you find.** + + - Last build date: `${{ steps.vars.outputs.date_now }}` + - Reference commit: ${{ github.sha }} + + *** + ## Patch notes: + ${{ steps.patch_notes.outputs.content }} + + name: Updated tested build - ${{ steps.version.outputs.v-version }} (${{ steps.vars.outputs.sha_short }}) + prerelease: false + removeArtifacts: true + tag: ${{ steps.version.outputs.v-version }} diff --git a/.gitignore b/.gitignore index a71ef047..3abda3d9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ __pycache__ log.txt /lock.file settings.json -/lang/English.json +#/lang/English.json # AppImage /AppDir /appimage-builder diff --git a/README.md b/README.md index 2dc95678..1cb1ddf1 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,12 @@ # Twitch Drops Miner +Thanks to @DevilXD and other contributors from the [original repo](https://github.com/DevilXD/TwitchDropsMiner) for the vast majority of the code. + This application allows you to AFK mine timed Twitch drops, without having to worry about switching channels when the one you were watching goes offline, claiming the drops, or even receiving the stream data itself. This helps both you and Twitch save on bandwidth and hassle. Everyone wins! ### How It Works: -Every ~60 seconds, the application sends a "minute watched" event to the channel that's currently being watched - this is enough to advance the drops. Note that this completely bypasses the need to download any actual stream video and sound. To keep the status (ONLINE or OFFLINE) of the channels up-to-date, there's a websocket connection established that receives events about streams going up or down, or updates regarding the current amount of viewers. +Every ~20 seconds, the application asks Twitch for a URL to the raw stream data of the channel currently being watched. It then fetches the metadata of this data stream - this is enough to advance the drops. Note that this completely bypasses the need to download any actual stream video and sound. To keep the status (ONLINE or OFFLINE) of the channels up-to-date, there's a websocket connection established that receives events about streams going up or down, or updates regarding the current amount of viewers. ### Features: @@ -30,6 +32,8 @@ Every ~60 seconds, the application sends a "minute watched" event to the channel ![Main](https://user-images.githubusercontent.com/4180725/164298155-c0880ad7-6423-4419-8d73-f3c053730a1b.png) ![Inventory](https://user-images.githubusercontent.com/4180725/164298315-81cae0d2-24a4-4822-a056-154fd763c284.png) ![Settings](https://user-images.githubusercontent.com/4180725/164298391-b13ad40d-3881-436c-8d4c-34e2bbe33a78.png) +![Help](https://github.com/Windows200000/TwitchDropsMiner-updated/assets/72623832/ca1c25e1-650f-415b-ab9d-8cfc001fc7e6) + ### Notes: @@ -129,3 +133,5 @@ if they aren't already there. Doing so ensures proper markdown rendering on Gith @casungo - For the entirety of the Italian (Italiano) translation. @Bamboozul - For the entirety of the Arabic (العربية) translation. @Kjerne - For the entirety of the Danish (Dansk) translation. + +For updating Translations: @Kuddus73, @VSeryi, @Windows200000, @BreakshadowCN, @kilroy98, @zelda0079, @Calvineries, @notNSANE, @ElvisDesigns, @DogancanYr, @Nollasko, @rvpv, @flxderdev, @5wi5wi, @fgr1178707QQ, @Suz1e, @Patriot99 diff --git a/build.spec b/build.spec index e14aac63..b8b4f1de 100644 --- a/build.spec +++ b/build.spec @@ -23,8 +23,7 @@ to_add: list[tuple[Path, str, bool]] = [ (Path(SITE_PACKAGES_PATH, "seleniumwire/ca.key"), "./seleniumwire", False), ] for lang_filepath in WORKING_DIR.joinpath("lang").glob("*.json"): - if lang_filepath.stem != DEFAULT_LANG: - to_add.append((lang_filepath, "lang", True)) + to_add.append((lang_filepath, "lang", True)) # ensure the required to-be-added data exists datas: list[tuple[Path, str]] = [] diff --git a/cache.py b/cache.py index f33cbb12..7c272579 100644 --- a/cache.py +++ b/cache.py @@ -32,6 +32,17 @@ class ExpiringHash(TypedDict): default_database: Hashes = {} +class CurrentSeconds: + LIFETIME = timedelta(days=7) + + def set_current_seconds(value): + global current_seconds + current_seconds = value + + def get_current_seconds(): + return current_seconds + + class ImageCache: LIFETIME = timedelta(days=7) diff --git a/channel.py b/channel.py index 0550aa15..7aa594bc 100644 --- a/channel.py +++ b/channel.py @@ -3,6 +3,7 @@ import re import asyncio import logging +import validators from base64 import b64encode from functools import cached_property from typing import Any, SupportsInt, TYPE_CHECKING @@ -377,6 +378,58 @@ def _payload(self) -> JsonType: return {"data": (b64encode(json_minify(payload).encode("utf8"))).decode("utf8")} async def send_watch(self) -> bool: + """ + Start of fix for 2024/5 API Change + """ + try: + response: JsonType = await self._twitch.gql_request( # Gets signature and value + GQL_OPERATIONS["PlaybackAccessToken"].with_variables({"login": self._login}) + ) + except MinerException as exc: + raise MinerException(f"Channel: {self._login}") from exc + signature: JsonType | None = response["data"]['streamPlaybackAccessToken']["signature"] + value: JsonType | None = response["data"]['streamPlaybackAccessToken']["value"] + if not signature or not value: + return False + + RequestBroadcastQualitiesURL = f"https://usher.ttvnw.net/api/channel/hls/{self._login}.m3u8?sig={signature}&token={value}" + + try: + async with self._twitch.request( # Gets list of streams + "GET", RequestBroadcastQualitiesURL + ) as response1: + BroadcastQualities = await response1.text() + except RequestException: + return False + + BroadcastLowestQualityURL = BroadcastQualities.split("\n")[-1] # Just takes the last line, this could probably be handled better in the future + if not validators.url(BroadcastLowestQualityURL): + return False + + try: + async with self._twitch.request( # Gets actual streams + "GET", BroadcastLowestQualityURL + ) as response2: + StreamURLList = await response2.text() + except RequestException: + return False + + StreamLowestQualityURL = StreamURLList.split("\n")[-2] # For whatever reason this includes a blank line at the end, this should probably be handled better in the future + if not validators.url(StreamLowestQualityURL): + return False + + try: + async with self._twitch.request( # Downloads the stream + "HEAD", StreamLowestQualityURL + ) as response3: # I lied, well idk, but this code doesn't listen for the actual video data + return response3.status == 200 + except RequestException: + return False + """ + End of fix for 2024/5 API Change. + Old code below. + """ + """ This uses the encoded payload on spade url to simulate watching the stream. Optimally, send every 60 seconds to advance drops. diff --git a/constants.py b/constants.py index bad23184..7fc49fe9 100644 --- a/constants.py +++ b/constants.py @@ -116,7 +116,7 @@ def _merge_vars(base_vars: JsonType, vars: JsonType) -> None: PING_INTERVAL = timedelta(minutes=3) PING_TIMEOUT = timedelta(seconds=10) ONLINE_DELAY = timedelta(seconds=120) -WATCH_INTERVAL = timedelta(seconds=59) +WATCH_INTERVAL = timedelta(seconds=20) # Strings WINDOW_TITLE = f"Twitch Drops Miner v{__version__} (by DevilXD)" # Logging @@ -238,6 +238,18 @@ def with_variables(self, variables: JsonType) -> GQLOperation: GQL_OPERATIONS: dict[str, GQLOperation] = { + # retuns PlaybackAccessToken_Template, for fix 2024/5 + "PlaybackAccessToken": GQLOperation( + "PlaybackAccessToken", + "3093517e37e4f4cb48906155bcd894150aef92617939236d2508f3375ab732ce", + variables={ + "isLive": True, + "login": "...", + "isVod": False, + "vodID": "", + "playerType": "site" + }, + ), # returns stream information for a particular channel "GetStreamInfo": GQLOperation( "VideoPlayerStreamInfoOverlayChannel", diff --git a/gui.py b/gui.py index ddc3be55..9afb401b 100644 --- a/gui.py +++ b/gui.py @@ -28,6 +28,7 @@ import win32con import win32gui +from cache import CurrentSeconds from translate import _ from cache import ImageCache from exceptions import ExitRequest @@ -352,12 +353,11 @@ def __init__( command: abc.Callable[[_T], Any] | None = None, default: str | None = None, relief: tk._Relief = "solid", - background: str = "white", **kwargs: Any, ): width = max((len(k) for k in options.keys()), default=20) super().__init__( - master, *args, background=background, relief=relief, width=width, **kwargs + master, *args, relief=relief, width=width, **kwargs ) self._menu_options: dict[str, _T] = options self._command = command @@ -667,6 +667,7 @@ def _update_time(self, seconds: int): drop_vars: _DropVars = self._vars["drop"] campaign_vars: _CampaignVars = self._vars["campaign"] dseconds = seconds % 60 + CurrentSeconds.set_current_seconds(dseconds) hours, minutes = self._divmod(drop_minutes, seconds) drop_vars["remaining"].set( _("gui", "progress", "remaining").format(time=f"{hours:>2}:{minutes:02}:{dseconds:02}") @@ -686,6 +687,7 @@ async def _timer_loop(self): self._timer_task = None def start_timer(self): + self._manager.print(f"Progress: {self._drop.current_minutes}/{self._drop.required_minutes} - {self._drop.campaign}") if self._timer_task is None: if self._drop is None or self._drop.remaining_minutes <= 0: # if we're starting the timer at 0 drop minutes, @@ -1047,12 +1049,32 @@ def get_title(self, drop: TimedDrop | None) -> str: if drop is None: return self.TITLE campaign = drop.campaign - return ( + title = ( f"{self.TITLE}\n" f"{campaign.game.name}\n" f"{drop.rewards_text()} " f"{drop.progress:.1%} ({campaign.claimed_drops}/{campaign.total_drops})" ) + if len(title) > 127: # ValueError: string too long (x, maximum length 128), but it only shows 127 + min_length = 30 + diff = len(title) - 127 + if (len(drop.rewards_text()) - diff) >= min_length + 1: # If we can trim the drop name to 20 chars + new_length = len(drop.rewards_text()) - diff - 1 # Length - Diff - Ellipsis (…) + title = ( + f"{self.TITLE}\n" + f"{campaign.game.name}\n" + f"{drop.rewards_text()[:new_length]}… " + f"{drop.progress:.1%} ({campaign.claimed_drops}/{campaign.total_drops})" + ) + else: # Trimming both + new_length = len(campaign.game.name) - (diff - len(drop.rewards_text()) + min_length + 1) - 1 # Campaign name - (Remaining diff from trimmed drop name) - Ellipsis + title = ( + f"{self.TITLE}\n" + f"{campaign.game.name[:new_length]}…\n" + f"{drop.rewards_text()[:min_length]}… " + f"{drop.progress:.1%} ({campaign.claimed_drops}/{campaign.total_drops})" + ) + return title def _start(self): loop = asyncio.get_running_loop() @@ -1454,8 +1476,10 @@ def proxy_validate(entry: PlaceholderEntry, settings: Settings) -> bool: class _SettingsVars(TypedDict): tray: IntVar proxy: StringVar + dark_theme: IntVar autostart: IntVar priority_only: IntVar + prioritize_by_ending_soonest: IntVar tray_notifications: IntVar @@ -1463,14 +1487,18 @@ class SettingsPanel: AUTOSTART_NAME: str = "TwitchDropsMiner" AUTOSTART_KEY: str = "HKCU/Software/Microsoft/Windows/CurrentVersion/Run" - def __init__(self, manager: GUIManager, master: ttk.Widget): + def __init__(self, manager: GUIManager, master: ttk.Widget, root: tk.Tk): + self._manager = manager + self._root = root self._twitch = manager._twitch self._settings: Settings = manager._twitch.settings self._vars: _SettingsVars = { "proxy": StringVar(master, str(self._settings.proxy)), "tray": IntVar(master, self._settings.autostart_tray), + "dark_theme": IntVar(master, self._settings.dark_theme), "autostart": IntVar(master, self._settings.autostart), "priority_only": IntVar(master, self._settings.priority_only), + "prioritize_by_ending_soonest": IntVar(master, self._settings.prioritize_by_ending_soonest), "tray_notifications": IntVar(master, self._settings.tray_notifications), } master.rowconfigure(0, weight=1) @@ -1493,18 +1521,25 @@ def __init__(self, manager: GUIManager, master: ttk.Widget): language_frame = ttk.Frame(center_frame2) language_frame.grid(column=0, row=0) ttk.Label(language_frame, text="Language 🌐 (requires restart): ").grid(column=0, row=0) - SelectMenu( + self._select_menu = SelectMenu( language_frame, default=_.current, options={k: k for k in _.languages}, command=lambda lang: setattr(self._settings, "language", lang), - ).grid(column=1, row=0) + ) + self._select_menu.grid(column=1, row=0) # checkboxes frame checkboxes_frame = ttk.Frame(center_frame2) checkboxes_frame.grid(column=0, row=1) ttk.Label( - checkboxes_frame, text=_("gui", "settings", "general", "autostart") + checkboxes_frame, text=_("gui", "settings", "general", "dark_theme") ).grid(column=0, row=(irow := 0), sticky="e") + ttk.Checkbutton( + checkboxes_frame, variable=self._vars["dark_theme"], command=self.change_theme + ).grid(column=1, row=irow, sticky="w") + ttk.Label( + checkboxes_frame, text=_("gui", "settings", "general", "autostart") + ).grid(column=0, row=(irow := irow + 1), sticky="e") ttk.Checkbutton( checkboxes_frame, variable=self._vars["autostart"], command=self.update_autostart ).grid(column=1, row=irow, sticky="w") @@ -1528,6 +1563,12 @@ def __init__(self, manager: GUIManager, master: ttk.Widget): ttk.Checkbutton( checkboxes_frame, variable=self._vars["priority_only"], command=self.priority_only ).grid(column=1, row=irow, sticky="w") + ttk.Label( + checkboxes_frame, text=_("gui", "settings", "general", "prioritize_by_ending_soonest") + ).grid(column=0, row=(irow := irow + 1), sticky="e") + ttk.Checkbutton( + checkboxes_frame, variable=self._vars["prioritize_by_ending_soonest"], command=self.prioritize_by_ending_soonest + ).grid(column=1, row=irow, sticky="w") # proxy frame proxy_frame = ttk.Frame(center_frame2) proxy_frame.grid(column=0, row=2) @@ -1637,6 +1678,13 @@ def _get_autostart_path(self, tray: bool) -> str: self_path += " --tray" return self_path + def change_theme(self): + self._settings.dark_theme = bool(self._vars["dark_theme"].get()) + if self._settings.dark_theme: + set_theme(self._root, self._manager, "dark") + else: + set_theme(self._root, self._manager, "light") + def update_autostart(self) -> None: enabled = bool(self._vars["autostart"].get()) tray = bool(self._vars["tray"].get()) @@ -1740,6 +1788,9 @@ def priority_delete(self) -> None: def priority_only(self) -> None: self._settings.priority_only = bool(self._vars["priority_only"].get()) + def prioritize_by_ending_soonest(self) -> None: + self._settings.prioritize_by_ending_soonest = bool(self._vars["prioritize_by_ending_soonest"].get()) + def exclude_add(self) -> None: game_name: str = self._exclude_entry.get() if not game_name: @@ -1878,14 +1929,14 @@ def __init__(self, twitch: Twitch): # Image cache for displaying images self._cache = ImageCache(self) - # style adjustements + # style adjustments self._style = style = ttk.Style(root) default_font = nametofont("TkDefaultFont") # theme theme = '' # theme = style.theme_names()[6] # style.theme_use(theme) - # fix treeview's background color from tags not working (also see '_fixed_map') + # Fix treeview's background color from tags not working (also see '_fixed_map') style.map( "Treeview", foreground=self._fixed_map("foreground"), @@ -1948,7 +1999,7 @@ def __init__(self, twitch: Twitch): self.tabs.add_tab(inv_frame, name=_("gui", "tabs", "inventory")) # Settings tab settings_frame = ttk.Frame(root_frame, padding=8) - self.settings = SettingsPanel(self, settings_frame) + self.settings = SettingsPanel(self, settings_frame, root) self.tabs.add_tab(settings_frame, name=_("gui", "tabs", "settings")) # Help tab help_frame = ttk.Frame(root_frame, padding=8) @@ -1995,6 +2046,11 @@ def __init__(self, twitch: Twitch): else: self._root.after_idle(self._root.deiconify) + if self._twitch.settings.dark_theme: + set_theme(root, self, "dark") + else: + set_theme(root, self, "default") # + # https://stackoverflow.com/questions/56329342/tkinter-treeview-background-tag-not-working def _fixed_map(self, option): # Fix for setting text colour for Tkinter 8.6.9 @@ -2129,10 +2185,116 @@ def clear_drop(self): self.tray.update_title(None) def print(self, message: str): + print(f"{datetime.now().strftime('%Y-%m-%d %X')}: {message}") # print to our custom output self.output.print(message) +def set_theme(root, manager, name): + style = ttk.Style(root) + if not hasattr(set_theme, "default_style"): + set_theme.default_style = style.theme_use() # "Themes" is more fitting for the recolour and "Style" for the button style. + + default_font = nametofont("TkDefaultFont") + large_font = default_font.copy() + large_font.config(size=12) + link_font = default_font.copy() + link_font.config(underline=True) + + def configure_combobox_list(combobox, flag, value): + combobox.update_idletasks() + popdown_window = combobox.tk.call("ttk::combobox::PopdownWindow", combobox) + listbox = f"{popdown_window}.f.l" + combobox.tk.call(listbox, "configure", flag, value) + + # Style options, !!!"background" and "bg" is not interchangable for some reason!!! + if name == "dark": + bg_grey = "#181818" + active_grey = "#2b2b2b" + # General + style.theme_use('alt') # We have to switch the theme, because OS-defaults ("vista") don't support certain customisations, like Treeview-fieldbackground etc. + style.configure('.', background=bg_grey, foreground="white") + style.configure("Link.TLabel", font=link_font, foreground="#00aaff") + # Buttons + style.map("TButton", + background=[("active", active_grey)]) + # Tabs + style.configure("TNotebook.Tab", background=bg_grey) + style.map("TNotebook.Tab", + background=[("selected", active_grey)]) + # Checkboxes + style.configure("TCheckbutton", foreground="black") # The checkbox has to be white since it's an image, so the tick has to be black + style.map("TCheckbutton", + background=[('active', active_grey)]) + # Output field + manager.output._text.configure(bg=bg_grey, fg="white", selectbackground=active_grey) + # Include/Exclude lists + manager.settings._exclude_list.configure(bg=bg_grey, fg="white") + manager.settings._priority_list.configure(bg=bg_grey, fg="white") + # Channel list + style.configure('Treeview', background=bg_grey, fieldbackground=bg_grey) + manager.channels._table + # Inventory + manager.inv._canvas.configure(bg=bg_grey) + # Scroll bars + style.configure("TScrollbar", foreground="white", troughcolor=bg_grey, bordercolor=bg_grey, arrowcolor="white") + style.map("TScrollbar", + background=[("active", bg_grey), ("!active", bg_grey)]) + # Language selection box _select_menu + manager.settings._select_menu.configure(bg=bg_grey, fg="white", activebackground=active_grey, activeforeground="white") # Couldn't figure out how to change the border, so it stays black + for index in range(manager.settings._select_menu.menu.index("end")+1): + manager.settings._select_menu.menu.entryconfig(index, background=bg_grey, activebackground=active_grey, foreground="white") + # Proxy field + style.configure("TEntry", foreground="white", selectbackground=active_grey, fieldbackground=bg_grey) + # Include/Exclude box + style.configure("TCombobox", foreground="white", selectbackground=active_grey, fieldbackground=bg_grey, arrowcolor="white") + style.map("TCombobox", background=[("active", active_grey), ("disabled", bg_grey)]) + # Include list + configure_combobox_list(manager.settings._priority_entry, "-background", bg_grey) + configure_combobox_list(manager.settings._priority_entry, "-foreground", "white") + configure_combobox_list(manager.settings._priority_entry, "-selectbackground", active_grey) + # Exclude list + configure_combobox_list(manager.settings._exclude_entry, "-background", bg_grey) + configure_combobox_list(manager.settings._exclude_entry, "-foreground", "white") + configure_combobox_list(manager.settings._exclude_entry, "-selectbackground", active_grey) + + else: # When creating a new theme, additional values might need to be set, so the default theme remains consistent + # General + style.theme_use(set_theme.default_style) + style.configure('.', background="#f0f0f0", foreground="#000000") + # Buttons + style.map("TButton", + background=[("active", "#ffffff")]) + # Tabs + style.configure("TNotebook.Tab", background="#f0f0f0") + style.map("TNotebook.Tab", + background=[("selected", "#ffffff")]) + # Checkboxes don't need to be reverted + # Output field + manager.output._text.configure(bg="#ffffff", fg="#000000") + # Include/Exclude lists + manager.settings._exclude_list.configure(bg="#ffffff", fg="#000000") + manager.settings._priority_list.configure(bg="#ffffff", fg="#000000") + # Channel list doesn't need to be reverted + # Inventory + manager.inv._canvas.configure(bg="#f0f0f0") + # Scroll bars don't need to be reverted + # Language selection box _select_menu + manager.settings._select_menu.configure(bg="#ffffff", fg="black", activebackground="#f0f0f0", activeforeground="black") # Couldn't figure out how to change the border, so it stays black + for index in range(manager.settings._select_menu.menu.index("end")+1): + manager.settings._select_menu.menu.entryconfig(index, background="#f0f0f0", activebackground="#0078d7", foreground="black") + # Proxy field doesn't need to be reverted + # Include/Exclude dropdown - Only the lists have to be reverted + # Include list + configure_combobox_list(manager.settings._priority_entry, "-background", "white") + configure_combobox_list(manager.settings._priority_entry, "-foreground", "black") + configure_combobox_list(manager.settings._priority_entry, "-selectbackground", "#0078d7") + # Exclude list + configure_combobox_list(manager.settings._exclude_entry, "-background", "white") + configure_combobox_list(manager.settings._exclude_entry, "-foreground", "black") + configure_combobox_list(manager.settings._exclude_entry, "-selectbackground", "#0078d7") + + ################### # GUI MANAGER END # ################### @@ -2254,11 +2416,14 @@ async def main(exit_event: asyncio.Event): tray=False, priority=[], proxy=URL(), + dark_theme=False, autostart=False, language="English", priority_only=False, + prioritize_by_ending_soonest=False, autostart_tray=False, exclude={"Lit Game"}, + tray_notifications=True ) ) mock.change_state = lambda state: mock.gui.print(f"State change: {state.value}") diff --git a/lang/Deutsch.json b/lang/Deutsch.json index 3b7fe09e..ae59d8cb 100644 --- a/lang/Deutsch.json +++ b/lang/Deutsch.json @@ -1,161 +1,164 @@ -{ - "english_name": "German", - "status": { - "terminated": "\nAnwendung gestoppt.\nFenster schließen, um die Anwendung zu beenden", - "watching": "{channel} wird zugesehen", - "goes_online": "{channel} ist ONLINE gegangen, wechseln...", - "goes_offline": "{channel} ist OFFLINE gegangen, wechseln...", - "claimed_drop": "Drop abgeholt: {drop}", - "claimed_points": "Kanal-Punkte verdient: {points}", - "earned_points": "Verdiente Kanal-Punkte fürs zuschauen: {points} | Summe: {balance}", - "no_channel": "Keine teilnehmenden Kanäle online. Warten auf Kanäle...", - "no_campaign": "Keine aktiven Kampagnen verfügbar. Warten auf neue Kampagne..." - }, - "login": { - "chrome": { - "startup": "Starte Chrome...", - "login_to_complete": "Erneut auf Anmelden drücken, um den Anmeldevorgang manuell abzuschließen.", - "no_token": "Es wurde kein Autorisierungs-Token gefunden.", - "closed_window": "Das Chrome-Fenster wurde geschlossen, bevor der Anmeldevorgang abgeschlossen werden konnte." - }, - "error_code": "Login-Fehlercode: {error_code}", - "unexpected_content": "Unerwarteter Inhaltstyp zurückgegeben, normalerweise aufgrund einer Weiterleitung.\nIst ein Login für den Internetzugang erforderlich?", - "incorrect_login_pass": "Falscher Benutzername oder Passwort.", - "incorrect_email_code": "Falscher E-Mail Code.", - "incorrect_twofa_code": "Falscher 2FA Code.", - "email_code_required": "E-Mail Code erforderlich. Bitte E-Mail prüfen.", - "twofa_code_required": "2FA Token erforderlich." - }, - "error": { - "captcha": "Der Anmeldeversuch wurde durch CAPTCHA verweigert.\nBitte versuche es in mindestens 12 Stunden erneut.", - "site_down": "Twitch ist nicht erreichbar. Erneuter Versuch in {seconds} Sekunden...", - "no_connection": "Keine Verbindung zu Twitch möglich. Erneuter Versuch in {seconds} Sekunden..." - }, - "gui": { - "output": "Protokoll", - "status": { - "name": "Status", - "idle": "Im Leerlauf", - "exiting": "Beenden...", - "terminated": "Abgebrochen", - "cleanup": "Kanäle aufräumen..", - "gathering": "Kanäle sammeln...", - "switching": "Wechsel des Kanals...", - "fetching_inventory": "Lade Inventar...", - "fetching_campaigns": "Lade Kampagnen...", - "adding_campaigns": "Kampagnen dem Inventar hinzufügen... {counter}" - }, - "tabs": { - "main": "Hauptseite", - "inventory": "Inventar", - "settings": "Einstellungen", - "help": "Hilfe" - }, - "tray": { - "notification_title": "Drop abgeholt", - "minimize": "Minimiere ins System Tray", - "show": "Anzeigen", - "quit": "Beenden" - }, - "login": { - "name": "Login", - "labels": "Status:\nBenutzer ID:", - "logged_in": "Angemeldet", - "logged_out": "Abgemeldet", - "logging_in": "Anmelden...", - "required": "Anmeldung erforderlich", - "request": "Bitte einloggen um fortzufahren.", - "username": "Benutzername", - "password": "Passwort", - "twofa_code": "2FA Code (optional)", - "button": "Anmelden" - }, - "websocket": { - "name": "WebSocket Status", - "websocket": "WebSocket #{id}:", - "initializing": "Initialisieren...", - "connected": "Verbunden", - "disconnected": "Verbindung verloren", - "connecting": "Verbinden...", - "disconnecting": "Verbindung trennen...", - "reconnecting": "Neu verbinden..." - }, - "progress": { - "name": "Kampagnen-Fortschritt", - "drop": "Drop:", - "game": "Spiel:", - "campaign": "Kampagne:", - "remaining": "{time} verbleibend", - "drop_progress": "Fortschritt:", - "campaign_progress": "Fortschritt:" - }, - "channels": { - "name": "Kanäle", - "switch": "Wechseln", - "load_points": "Lade Punkte", - "online": "ONLINE ✔", - "pending": "OFFLINE ⏳", - "offline": "OFFLINE ❌", - "headings": { - "channel": "Kanal", - "status": "Status", - "game": "Spiel", - "viewers": "Zuschauer", - "points": "Punkte" - } - }, - "inventory": { - "filter": { - "name": "Filter", - "show": "Anzeigen:", - "not_linked": "Nicht verbunden", - "upcoming": "Zukünftig", - "expired": "Abgelaufen", - "excluded": "Ausgeschlossen", - "finished": "Abgeholt", - "refresh": "Aktualisieren" - }, - "status": { - "linked": "Verknüpft ✔", - "not_linked": "Nicht verknüpft ❌", - "active": "Aktiv ✔", - "upcoming": "Zukünftig ⏳", - "expired": "Abgelaufen ❌", - "claimed": "Abgeholt ✔", - "ready_to_claim": "Bereit zum abholen ⏳" - }, - "starts": "Beginnt: {time}", - "ends": "Endet: {time}", - "allowed_channels": "Teilnehmende Kanäle:", - "all_channels": "Alle", - "and_more": "und {amount} weitere...", - "percent_progress": "{percent} von {minutes} Minuten", - "minutes_progress": "{minutes} Minuten" - }, - "settings": { - "general": { - "name": "Allgemein", - "autostart": "Autostart: ", - "tray": "Autostart ins System Tray: ", - "priority_only": "Nur Priorität: ", - "proxy": "Proxy (Erfordert Neustart):" - }, - "game_name": "Spiel", - "priority": "Priorität", - "exclude": "Ausschließen", - "reload": "Neu laden", - "reload_text": "Die meisten Änderungen erfordern ein neu laden, um sofort wirksam zu werden: " - }, - "help": { - "links": { - "name": "Hilfreiche Links", - "inventory": "Twitch Inventar ansehen", - "campaigns": "Alle Twitch-Kampagnen ansehen" - }, - "how_it_works": "So funktioniert's", - "how_it_works_text": "Alle ~60 Sekunden sendet die Anwendung ein \"Minute zugesehen\" Ereignis an den Kanal, dem gerade zugesehen wird.\nDies reicht aus, um den Drop voranzutreiben. Auf diese Weise ist es nicht nötig den Stream herunterzuladen und spart Bandbreite.\nUm den Online- oder Offline-Status der Kanäle aktuell zu halten, wird eine Websocket-Verbindung eingerichtet,\ndie die Kanäle auf ihren Status überprüft.", - "getting_started": "Erste Schritte", - "getting_started_text": "• In der Anwendung anmelden.\n• Stelle sicher, dass das Twitch-Konto mit allen Kampagnen verknüpft ist, an denen Interesse besteht.\n• Sollen alle Drops bearbeitet werden, entferne den Haken bei \"Nur Priorität\" und drücke \"Neu laden\".\n• Sollen nur bestimmte Spiele in betracht gezogen werden, verwende die \"Priorität\" Liste um die Wahl nach Spielen einzugrenzen.\n• Die Liste priorisiert von oben nach unten.\n• Die Option \"Nur Priorität\" verhindert, dass Spiele, die nicht auf der Prioritätenliste stehen, bearbeitet werden.\n• Mit der Liste \"Ausschließen\", ist es möglich Spiele zu filtern, die niemals in betracht gezogen werden sollen.\n• Wenn Listen oder Optionen angepasst wurden, muss \"Neu laden\" gedrückt werden, damit die Änderungen übernommen werden." - } - } -} +{ + "english_name": "German", + "status": { + "terminated": "\nAnwendung gestoppt.\nFenster schließen, um die Anwendung zu beenden", + "watching": "{channel} wird zugesehen", + "goes_online": "{channel} ist ONLINE gegangen, wechseln...", + "goes_offline": "{channel} ist OFFLINE gegangen, wechseln...", + "claimed_drop": "Drop abgeholt: {drop}", + "claimed_points": "Kanal-Punkte verdient: {points}", + "earned_points": "Verdiente Kanal-Punkte fürs zuschauen: {points} | Summe: {balance}", + "no_channel": "Keine teilnehmenden Kanäle online. Warten auf Kanäle...", + "no_campaign": "Keine aktiven Kampagnen verfügbar. Warten auf neue Kampagne..." + }, + "login": { + "unexpected_content": "Unerwarteter Inhaltstyp zurückgegeben, normalerweise aufgrund einer Weiterleitung.\nIst ein Login für den Internetzugang erforderlich?", + "chrome": { + "startup": "Starte Chrome...", + "login_to_complete": "Erneut auf Anmelden drücken, um den Anmeldevorgang manuell abzuschließen.", + "no_token": "Es wurde kein Autorisierungs-Token gefunden.", + "closed_window": "Das Chrome-Fenster wurde geschlossen, bevor der Anmeldevorgang abgeschlossen werden konnte." + }, + "error_code": "Login-Fehlercode: {error_code}", + "incorrect_login_pass": "Falscher Benutzername oder Passwort.", + "incorrect_email_code": "Falscher E-Mail Code.", + "incorrect_twofa_code": "Falscher 2FA Code.", + "email_code_required": "E-Mail Code erforderlich. Bitte E-Mail prüfen.", + "twofa_code_required": "2FA Token erforderlich." + }, + "error": { + "captcha": "Der Anmeldeversuch wurde durch CAPTCHA verweigert.\nBitte versuche es in mindestens 12 Stunden erneut.", + "site_down": "Twitch ist nicht erreichbar. Erneuter Versuch in {seconds} Sekunden...", + "no_connection": "Keine Verbindung zu Twitch möglich. Erneuter Versuch in {seconds} Sekunden..." + }, + "gui": { + "output": "Protokoll", + "status": { + "name": "Status", + "idle": "Im Leerlauf", + "exiting": "Beenden...", + "terminated": "Abgebrochen", + "cleanup": "Kanäle aufräumen..", + "gathering": "Kanäle sammeln...", + "switching": "Wechsel des Kanals...", + "fetching_inventory": "Lade Inventar...", + "fetching_campaigns": "Lade Kampagnen...", + "adding_campaigns": "Kampagnen dem Inventar hinzufügen... {counter}" + }, + "tabs": { + "main": "Hauptseite", + "inventory": "Inventar", + "settings": "Einstellungen", + "help": "Hilfe" + }, + "tray": { + "notification_title": "Drop abgeholt", + "minimize": "Minimiere ins System Tray", + "show": "Anzeigen", + "quit": "Beenden" + }, + "login": { + "name": "Login", + "labels": "Status:\nBenutzer ID:", + "logged_in": "Angemeldet", + "logged_out": "Abgemeldet", + "logging_in": "Anmelden...", + "required": "Anmeldung erforderlich", + "request": "Bitte einloggen um fortzufahren.", + "username": "Benutzername", + "password": "Passwort", + "twofa_code": "2FA Code (optional)", + "button": "Anmelden" + }, + "websocket": { + "name": "WebSocket Status", + "websocket": "WebSocket #{id}:", + "initializing": "Initialisieren...", + "connected": "Verbunden", + "disconnected": "Verbindung verloren", + "connecting": "Verbinden...", + "disconnecting": "Verbindung trennen...", + "reconnecting": "Neu verbinden..." + }, + "progress": { + "name": "Kampagnen-Fortschritt", + "drop": "Drop:", + "game": "Spiel:", + "campaign": "Kampagne:", + "remaining": "{time} verbleibend", + "drop_progress": "Fortschritt:", + "campaign_progress": "Fortschritt:" + }, + "channels": { + "name": "Kanäle", + "switch": "Wechseln", + "load_points": "Lade Punkte", + "online": "ONLINE ✔", + "pending": "OFFLINE ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "Kanal", + "status": "Status", + "game": "Spiel", + "viewers": "Zuschauer", + "points": "Punkte" + } + }, + "inventory": { + "filter": { + "name": "Filter", + "show": "Anzeigen:", + "not_linked": "Nicht verbunden", + "upcoming": "Zukünftig", + "expired": "Abgelaufen", + "excluded": "Ausgeschlossen", + "finished": "Abgeholt", + "refresh": "Aktualisieren" + }, + "status": { + "linked": "Verknüpft ✔", + "not_linked": "Nicht verknüpft ❌", + "active": "Aktiv ✔", + "upcoming": "Zukünftig ⏳", + "expired": "Abgelaufen ❌", + "claimed": "Abgeholt ✔", + "ready_to_claim": "Bereit zum abholen ⏳" + }, + "starts": "Beginnt: {time}", + "ends": "Endet: {time}", + "allowed_channels": "Teilnehmende Kanäle:", + "all_channels": "Alle", + "and_more": "und {amount} weitere...", + "percent_progress": "{percent} von {minutes} Minuten", + "minutes_progress": "{minutes} Minuten" + }, + "settings": { + "general": { + "name": "Allgemein", + "dark_theme": "Dunkler Design: ", + "autostart": "Autostart: ", + "tray": "Autostart ins System Tray: ", + "tray_notifications": "System Tray Benachrichtigungen:", + "priority_only": "Nur Priorität: ", + "prioritize_by_ending_soonest": "Kampagnen nach Ende priorisieren: ", + "proxy": "Proxy (Erfordert Neustart):" + }, + "game_name": "Spiel", + "priority": "Priorität", + "exclude": "Ausschließen", + "reload": "Neu laden", + "reload_text": "Die meisten Änderungen erfordern ein neu laden, um sofort wirksam zu werden: " + }, + "help": { + "links": { + "name": "Hilfreiche Links", + "inventory": "Twitch Inventar ansehen", + "campaigns": "Alle Twitch-Kampagnen ansehen" + }, + "how_it_works": "So funktioniert's", + "how_it_works_text": "Alle ~20 Sekunden fragt die Anwendung Twitch nach einer URL für die Rohdaten des Streams von dem Kanal, dem gerade zugesehen wird. Dann fordert sie die Metadaten dieses Datenstroms an. Dies reicht aus, um den Drop voranzutreiben. Auf diese Weise ist es nicht nötig den Stream herunterzuladen und spart Bandbreite.\nUm den Online- oder Offline-Status der Kanäle aktuell zu halten, wird eine Websocket-Verbindung eingerichtet,\ndie die Kanäle auf ihren Status überprüft.", + "getting_started": "Erste Schritte", + "getting_started_text": "• In der Anwendung anmelden.\n• Stelle sicher, dass das Twitch-Konto mit allen Kampagnen verknüpft ist, an denen Interesse besteht.\n• Sollen alle Drops bearbeitet werden, entferne den Haken bei \"Nur Priorität\" und drücke \"Neu laden\".\n• Sollen nur bestimmte Spiele in betracht gezogen werden, verwende die \"Priorität\" Liste um die Wahl nach Spielen einzugrenzen.\n• Die Liste priorisiert von oben nach unten.\n• Die Option \"Nur Priorität\" verhindert, dass Spiele, die nicht auf der Prioritätenliste stehen, bearbeitet werden.\n• Mit der Liste \"Ausschließen\", ist es möglich Spiele zu filtern, die niemals in betracht gezogen werden sollen.\n• Wenn Listen oder Optionen angepasst wurden, muss \"Neu laden\" gedrückt werden, damit die Änderungen übernommen werden." + } + } +} diff --git a/lang/English.json b/lang/English.json new file mode 100644 index 00000000..b231dcef --- /dev/null +++ b/lang/English.json @@ -0,0 +1,164 @@ +{ + "english_name": "English", + "status": { + "terminated": "\nApplication Terminated.\nClose the window to exit the application.", + "watching": "Watching: {channel}", + "goes_online": "{channel} goes ONLINE, switching...", + "goes_offline": "{channel} goes OFFLINE, switching...", + "claimed_drop": "Claimed drop: {drop}", + "claimed_points": "Claimed bonus points: {points}", + "earned_points": "Earned points for watching: {points}, total: {balance}", + "no_channel": "No available channels to watch. Waiting for an ONLINE channel...", + "no_campaign": "No active campaigns to mine drops for. Waiting for an active campaign..." + }, + "login": { + "unexpected_content": "Unexpected content type returned, usually due to being redirected. Do you need to login for internet access?", + "chrome": { + "startup": "Opening Chrome...", + "login_to_complete": "Complete the login procedure manually by pressing the Login button again.", + "no_token": "No authorization token could be found.", + "closed_window": "The Chrome window was closed before the login procedure could be completed." + }, + "error_code": "Login error code: {error_code}", + "incorrect_login_pass": "Incorrect username or password.", + "incorrect_email_code": "Incorrect email code.", + "incorrect_twofa_code": "Incorrect 2FA code.", + "email_code_required": "Email code required. Check your email.", + "twofa_code_required": "2FA token required." + }, + "error": { + "captcha": "Your login attempt was denied by CAPTCHA.\nPlease try again in 12+ hours.", + "site_down": "Twitch is down, retrying in {seconds} seconds...", + "no_connection": "Cannot connect to Twitch, retrying in {seconds} seconds..." + }, + "gui": { + "output": "Output", + "status": { + "name": "Status", + "idle": "Idle", + "exiting": "Exiting...", + "terminated": "Terminated", + "cleanup": "Cleaning up channels...", + "gathering": "Gathering channels...", + "switching": "Switching the channel...", + "fetching_inventory": "Fetching inventory...", + "fetching_campaigns": "Fetching campaigns...", + "adding_campaigns": "Adding campaigns to inventory... {counter}" + }, + "tabs": { + "main": "Main", + "inventory": "Inventory", + "settings": "Settings", + "help": "Help" + }, + "tray": { + "notification_title": "Mined Drop", + "minimize": "Minimize to Tray", + "show": "Show", + "quit": "Quit" + }, + "login": { + "name": "Login Form", + "labels": "Status:\nUser ID:", + "logged_in": "Logged in", + "logged_out": "Logged out", + "logging_in": "Logging in...", + "required": "Login required", + "request": "Please log in to continue.", + "username": "Username", + "password": "Password", + "twofa_code": "2FA code (optional)", + "button": "Login" + }, + "websocket": { + "name": "Websocket Status", + "websocket": "Websocket #{id}:", + "initializing": "Initializing...", + "connected": "Connected", + "disconnected": "Disconnected", + "connecting": "Connecting...", + "disconnecting": "Disconnecting...", + "reconnecting": "Reconnecting..." + }, + "progress": { + "name": "Campaign Progress", + "drop": "Drop:", + "game": "Game:", + "campaign": "Campaign:", + "remaining": "{time} remaining", + "drop_progress": "Progress:", + "campaign_progress": "Progress:" + }, + "channels": { + "name": "Channels", + "switch": "Switch", + "load_points": "Load Points", + "online": "ONLINE \u2714", + "pending": "OFFLINE \u23f3", + "offline": "OFFLINE \u274c", + "headings": { + "channel": "Channel", + "status": "Status", + "game": "Game", + "viewers": "Viewers", + "points": "Points" + } + }, + "inventory": { + "filter": { + "name": "Filter", + "show": "Show:", + "not_linked": "Not linked", + "upcoming": "Upcoming", + "expired": "Expired", + "excluded": "Excluded", + "finished": "Finished", + "refresh": "Refresh" + }, + "status": { + "linked": "Linked \u2714", + "not_linked": "Not Linked \u274c", + "active": "Active \u2714", + "upcoming": "Upcoming \u23f3", + "expired": "Expired \u274c", + "claimed": "Claimed \u2714", + "ready_to_claim": "Ready to claim \u23f3" + }, + "starts": "Starts: {time}", + "ends": "Ends: {time}", + "allowed_channels": "Allowed Channels:", + "all_channels": "All", + "and_more": "and {amount} more...", + "percent_progress": "{percent} of {minutes} minutes", + "minutes_progress": "{minutes} minutes" + }, + "settings": { + "general": { + "name": "General", + "dark_theme": "Dark theme: ", + "autostart": "Autostart: ", + "tray": "Autostart into tray: ", + "tray_notifications": "Tray notifications: ", + "priority_only": "Priority Only: ", + "prioritize_by_ending_soonest": "Prioritize by ending soonest: ", + "proxy": "Proxy (requires restart):" + }, + "game_name": "Game name", + "priority": "Priority", + "exclude": "Exclude", + "reload": "Reload", + "reload_text": "Most changes require a reload to take an immediate effect: " + }, + "help": { + "links": { + "name": "Useful Links", + "inventory": "See Twitch inventory", + "campaigns": "See all campaigns and manage account links" + }, + "how_it_works": "How It Works", + "how_it_works_text": "Every ~20 seconds, the application asks Twitch for a URL to the raw stream data of the channel currently being watched. It then fetches the metadata of this data stream - this is enough to advance the drops. Note that this completely bypasses the need to download any actual stream video and sound. To keep the status (ONLINE or OFFLINE) of the channels up-to-date, there's a websocket connection established that receives events about streams going up or down, or updates regarding the current number of viewers.", + "getting_started": "Getting Started", + "getting_started_text": "1. Log in to the application.\n2. Ensure your Twitch account is linked to all campaigns you're interested in mining.\n3. If you're interested in just mining everything, uncheck \"Priority only\" and press \"Reload\".\n4. If you want to mine specific games first, use the \"Priority\" list to set up an ordered list of games of your choice. Games from the top of the list will be attempted to be mined first, before the ones lower down the list.\n5. Keep the \"Priority only\" option checked to avoid mining games that are not on the priority list. Or not - it's up to you.\n6. Use the \"Exclude\" list to tell the application which games should never be mined.\n7. Changing the contents of either of the lists or changing the state of the \"Priority only\" option, requires you to press \"Reload\" for the changes to take effect." + } + } +} \ No newline at end of file diff --git "a/lang/Espa\303\261ol.json" "b/lang/Espa\303\261ol.json" index 2ed514cb..b73859d7 100644 --- "a/lang/Espa\303\261ol.json" +++ "b/lang/Espa\303\261ol.json" @@ -1,162 +1,164 @@ { - "english_name": "Spanish", + "english_name": "Spanish", + "status": { + "terminated": "\nLa aplicación se ha detenido.\nPor favor, cierre la aplicación.", + "watching": "Viendo el canal: {channel}", + "goes_online": "El canal {channel} se ha conectado, cambiando...", + "goes_offline": "El canal {channel} se ha desconectado, cambiando...", + "claimed_drop": "Drop reclamado: {drop}", + "claimed_points": "Recompensa de puntos reclamados: {points}", + "earned_points": "Puntos obtenidos por ver el stream: {points} | Total: {balance}", + "no_channel": "No se ha encontrado un canal en directo para ver. \nEsperando un canal en directo...", + "no_campaign": "No se ha encontrado una campaña activa. \nEsperando una nueva campaña..." + }, + "login": { + "unexpected_content": "Se produjo un error inesperado, \ngeneralmente debido a una redirección.\n¿Necesitas un VPN o iniciar sesión para acceder a internet?", + "chrome": { + "startup": "Iniciando Chrome...", + "login_to_complete": "Por favor, presione Iniciar sesión nuevamente para \ncompletar el inicio de sesión.", + "no_token": "No se pudo obtener un token de autorización.", + "closed_window": "La ventana de Chrome se cerró antes de que \nse completara el inicio de sesión." + }, + "error_code": "Error de inicio de sesión: {error_code}", + "incorrect_login_pass": "El usuario o contraseña ingresada es incorrecto.", + "incorrect_email_code": "El código de verificación de email es incorrecto.", + "incorrect_twofa_code": "El código 2FA es incorrecto.", + "email_code_required": "Código de verificación de email requerido. \nPor favor, revise su email.", + "twofa_code_required": "Token 2FA requerido." + }, + "error": { + "captcha": "El inicio de sesión fue rechazado por CAPTCHA.\nPor favor, intente nuevamente en aprox. 12 horas.", + "site_down": "Twitch no está disponible. \nIntente de nuevo en {seconds} segundos...", + "no_connection": "No se ha podido conectar a Twitch. \nIntente de nuevo en {seconds} segundos..." + }, + "gui": { + "output": "Registros", "status": { - "terminated": "\nLa aplicación se ha detenido.\nPor favor, cierre la aplicación.", - "watching": "Mirando el canal: {channel}", - "goes_online": "El canal {channel} se ha conectado, cambiando...", - "goes_offline": "El canal {channel} se ha desconectado, cambiando...", - "claimed_drop": "Drop reclamado: {drop}", - "claimed_points": "Recompensa de puntos reclamados: {points}", - "earned_points": "Puntos obtenidos por mirar el stream: {points} | Total: {balance}", - "no_channel": "No se ha encontrado un canal en vivo para mirar. \nEsperando un canal en vivo...", - "no_campaign": "No se ha encontrado una campaña activa. \nEsperando una nueva campaña..." + "name": "Estado", + "idle": "En espera...", + "exiting": "Saliendo...", + "terminated": "Aplicación suspendida.", + "cleanup": "Limpiando canales...", + "gathering": "Buscando canales en directo...", + "switching": "Cambiando de canal...", + "fetching_inventory": "Obteniendo inventario...", + "fetching_campaigns": "Obteniendo campañas...", + "adding_campaigns": "Agregando lista de campañas al inventario... {counter}" + }, + "tabs": { + "main": "General", + "inventory": "Inventario", + "settings": "Configuración", + "help": "Ayuda" + }, + "tray": { + "notification_title": "Drop minado", + "minimize": "Minimizar a la bandeja", + "show": "Mostrar", + "quit": "Salir" }, "login": { - "chrome": { - "startup": "Iniciando Chrome...", - "login_to_complete": "Por favor, presione Iniciar sesión nuevamente para \ncompletar el inicio de sesión.", - "no_token": "No se pudo obtener un token de autorización.", - "closed_window": "La ventana de Chrome se cerró antes de que \nse completara el inicio de sesión." - }, - "error_code": "Error de inicio de sesión: {error_code}", - "unexpected_content": "Se produjo un error inesperado, \ngeneralmente debido a una redirección.\n¿Necesitas un VPN o iniciar sesión para acceder a internet?", - "incorrect_login_pass": "El usuario o contraseña ingresada es incorrecto.", - "incorrect_email_code": "El código de verificación de email es incorrecto.", - "incorrect_twofa_code": "El código 2FA es incorrecto.", - "email_code_required": "Código de verificación de email requerido. \nPor favor, revise su email.", - "twofa_code_required": "Token 2FA requerido." + "name": "Inicio de sesión", + "labels": "Estado:\nUsuario:", + "logged_in": "Conectado", + "logged_out": "Desconectado", + "logging_in": "Iniciando sesión...", + "required": "Se requiere inicio de sesión", + "request": "Por favor, inicie sesión para continuar.", + "username": "Usuario", + "password": "Contraseña", + "twofa_code": "Token 2FA (opcional)", + "button": "Iniciar sesión" + }, + "websocket": { + "name": "Estado del Websocket", + "websocket": "Websocket #{id}:", + "initializing": "Iniciando...", + "connected": "Conectado", + "disconnected": "Desconectado", + "connecting": "Conectando...", + "disconnecting": "Desconectando...", + "reconnecting": "Reconectando..." + }, + "progress": { + "name": "Progreso de la Campaña", + "drop": "Drop:", + "game": "Juego:", + "campaign": "Campaña:", + "remaining": "{time} restante", + "drop_progress": "Progreso:", + "campaign_progress": "Progreso:" + }, + "channels": { + "name": "Canales", + "switch": "Cambiar", + "load_points": "Cargar Puntos", + "online": "ONLINE ✔", + "pending": "OFFLINE ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "Canal", + "status": "Estado", + "game": "Juego", + "viewers": "Espectadores", + "points": "Puntos" + } + }, + "inventory": { + "filter": { + "name": "Filtro de campañas", + "show": "Mostrar:", + "not_linked": "No enlazado", + "upcoming": "Próximas", + "expired": "Expiradas", + "excluded": "Excluidas", + "finished": "Completadas", + "refresh": "Actualizar" + }, + "status": { + "linked": "Vinculado ✔", + "not_linked": "Sin vincular ❌", + "active": "Activo ✔", + "upcoming": "Próximamente ⏳", + "expired": "Expirado ❌", + "claimed": "Reclamado ✔", + "ready_to_claim": "Listo para reclamar ⏳" + }, + "starts": "Comienza: {time}", + "ends": "Termina: {time}", + "allowed_channels": "Canales permitidos:", + "all_channels": "Todos", + "and_more": "y {amount} más...", + "percent_progress": "{percent} de {minutes} minutos", + "minutes_progress": "{minutes} minutos" }, - "error": { - "captcha": "El inicio de sesión fue rechazado por CAPTCHA.\nPor favor, intente nuevamente en aprox. 12 horas.", - "site_down": "Twitch no está disponible. \nIntente de nuevo en {seconds} segundos...", - "no_connection": "No se ha podido conectar a Twitch. \nIntente de nuevo en {seconds} segundos..." + "settings": { + "general": { + "name": "Ajustes generales", + "dark_theme": "Tema oscuro: ", + "autostart": "Ejecutar al iniciar el sistema: ", + "tray": "Ejecutar en la bandeja del sistema: ", + "tray_notifications": "Mostrar notificaciones: ", + "priority_only": "Minar solo juegos preferidos: ", + "prioritize_by_ending_soonest": "Priorizar campañas por fecha de finalización: ", + "proxy": "Proxy (requiere reinicio):" + }, + "game_name": "Nombre del juego", + "priority": "Lista de juegos preferidos", + "exclude": "Lista de juegos excluidos", + "reload": "Recargar", + "reload_text": "La mayoría de los cambios requieren recargar o reiniciar la aplicación para que sean aplicados: " }, - "gui": { - "output": "Registros", - "status": { - "name": "Estado", - "idle": "En espera...", - "exiting": "Saliendo...", - "terminated": "Aplicación suspendida.", - "cleanup": "Limpiando canales...", - "gathering": "Buscando canales en vivo...", - "switching": "Cambiando de canal...", - "fetching_inventory": "Obteniendo inventario...", - "fetching_campaigns": "Obteniendo campañas...", - "adding_campaigns": "Agregando lista de campañas al inventario... {counter}" - }, - "tabs": { - "main": "General", - "inventory": "Inventario", - "settings": "Configuración", - "help": "Ayuda" - }, - "tray": { - "notification_title": "Drop minado", - "minimize": "Minimizar a la bandeja", - "show": "Mostrar", - "quit": "Salir" - }, - "login": { - "name": "Inicio de sesión", - "labels": "Estado:\nUsuario:", - "logged_in": "Conectado", - "logged_out": "Desconectado", - "logging_in": "Iniciando sesión...", - "required": "Se requiere inicio de sesión", - "request": "Por favor, inicie sesión para continuar.", - "username": "Usuario", - "password": "Contraseña", - "twofa_code": "Token 2FA (opcional)", - "button": "Iniciar sesión" - }, - "websocket": { - "name": "Estado del Websocket", - "websocket": "Websocket #{id}:", - "initializing": "Iniciando...", - "connected": "Conectado", - "disconnected": "Desconectado", - "connecting": "Conectando...", - "disconnecting": "Desconectando...", - "reconnecting": "Reconectando..." - }, - "progress": { - "name": "Progreso de la Campaña", - "drop": "Drop:", - "game": "Juego:", - "campaign": "Campaña:", - "remaining": "{time} restante", - "drop_progress": "Progreso:", - "campaign_progress": "Progreso:" - }, - "channels": { - "name": "Canales", - "switch": "Cambiar", - "load_points": "Cargar Puntos", - "online": "ONLINE ✔", - "pending": "OFFLINE ⏳", - "offline": "OFFLINE ❌", - "headings": { - "channel": "Canal", - "status": "Estado", - "game": "Juego", - "viewers": "Espectadores", - "points": "Puntos" - } - }, - "inventory": { - "filter": { - "name": "Filtro de campañas", - "show": "Mostrar:", - "not_linked": "No enlazado", - "upcoming": "Próximas", - "expired": "Expiradas", - "excluded": "Excluidas", - "finished": "Completadas", - "refresh": "Actualizar" - }, - "status": { - "linked": "Vinculado ✔", - "not_linked": "Sin vincular ❌", - "active": "Activo ✔", - "upcoming": "Próximamente ⏳", - "expired": "Expirado ❌", - "claimed": "Reclamado ✔", - "ready_to_claim": "Listo para reclamar ⏳" - }, - "starts": "Comienza: {time}", - "ends": "Termina: {time}", - "allowed_channels": "Canales permitidos:", - "all_channels": "Todos", - "and_more": "y {amount} más...", - "percent_progress": "{percent} de {minutes} minutos", - "minutes_progress": "{minutes} minutos" - }, - "settings": { - "general": { - "name": "Ajustes generales", - "autostart": "Ejecutar al iniciar el sistema: ", - "tray": "Ejecutar en la bandeja del sistema: ", - "tray_notifications": "Mostrar notificaciones: ", - "priority_only": "Minar solo juegos preferidos: ", - "proxy": "Proxy (requiere reinicio):" - }, - "game_name": "Nombre del juego", - "priority": "Lista de juegos preferidos", - "exclude": "Lista de juegos excluidos", - "reload": "Recargar", - "reload_text": "La mayoría de los cambios requieren recargar o reiniciar la aplicación para que sean aplicados: " - }, - "help": { - "links": { - "name": "Enlaces útiles", - "inventory": "Ver inventario de Twitch", - "campaigns": "Ver todas las campañas y administrar cuentas vinculadas" - }, - "how_it_works": "Cómo funciona", - "how_it_works_text": "Cada aproximadamente 60 segundos, la aplicación envía un \"minuto visto\" al canal que se está mirando actualmente. \nDe esta forma, no es necesario descargar el video o sonido del stream. Ahorrando ancho de banda al usuario. \nCon el fin de mantener actualizados los estados (ONLINE o OFFLINE) de los canales, se establece una conexión websocket, \nque recibe información de los streams para poder actualizar el estado, o cantidad de espectadores actuales.", - "getting_started": "Primeros pasos", - "getting_started_text": "1. Inicie sesión en la aplicación. \n2. Verifique que su cuenta de Twitch esté vinculada a todas las campañas deseadas a minar. \n3. Si desea minar todas las campañas, desmarque la opción \"Minar solo juegos preferidos\" y presione \"Recargar\". \n4. Si desea darle prioridad a una campaña específica, utilice la \"Lista de juegos preferidos\" para crear una lista de prioridad. \nLos juegos en la parte superior de la lista se intentarán minar antes de los que estén más abajo. \n5. Utilice la opción \"Minar solo juegos preferidos\" si desea evitar minar juegos que no estén en la lista de juegos preferidos. \n6. Utilice la \"Lista de juegos excluidos\" si desea evitar minar juegos que no estén en la lista de juegos excluidos. \n7. Al utilizar la opción \"Minar solo juegos preferidos\" o al cambiar el contenido de las listas, \nserá necesario presionar el botón \"Recargar\" para que los cambios sean aplicados." - } + "help": { + "links": { + "name": "Enlaces útiles", + "inventory": "Ver inventario de Twitch", + "campaigns": "Ver todas las campañas y administrar cuentas vinculadas" + }, + "how_it_works": "Cómo funciona", + "how_it_works_text": "Aproximadamente cada 20 segundos, la aplicación solicita a Twitch la URL de los datos del canal que estamos viendo. \nDe esta forma, obtenemos sus metadatos, lo que nos permite ahorrar en la descarga de video o audio del stream. \nPara mantener actualizados los estados (ONLINE o OFFLINE) de los canales, así como el número de espectadores, \nse establece una conexión WebSocket mediante de la cual recibimos la información actualizada de los streams.", + "getting_started": "Primeros pasos", + "getting_started_text": "1. Inicie sesión en la aplicación. \n2. Verifique que su cuenta de Twitch esté vinculada a todas las campañas deseadas a minar. \n3. Si desea minar todas las campañas, desmarque la opción \"Minar solo juegos preferidos\" y presione \"Recargar\". \n4. Si desea darle prioridad a una campaña específica, utilice la \"Lista de juegos preferidos\" para crear una lista de prioridad. \nLos juegos en la parte superior de la lista se intentarán minar antes de los que estén más abajo. \n5. Utilice la opción \"Minar solo juegos preferidos\" si desea evitar minar juegos que no estén en la lista de juegos preferidos. \n6. Utilice la \"Lista de juegos excluidos\" si desea evitar minar juegos que no estén en la lista de juegos excluidos. \n7. Al utilizar la opción \"Minar solo juegos preferidos\" o al cambiar el contenido de las listas, \nserá necesario presionar el botón \"Recargar\" para que los cambios sean aplicados." } + } } diff --git "a/lang/Fran\303\247ais.json" "b/lang/Fran\303\247ais.json" index 5f532e3a..238d9550 100644 --- "a/lang/Fran\303\247ais.json" +++ "b/lang/Fran\303\247ais.json" @@ -154,7 +154,7 @@ "campaigns": "Afficher toutes les campagnes et gérer les comptes associés" }, "how_it_works": "Comment ça fonctionne", - "how_it_works_text": "Environ toutes les ~60 secondes, l'application envoie un événement \"minute regardée\" à la chaîne qui est actuellement en cours de visionnage - ce qui suffit pour faire avancer les drops. Notez que cela contourne complètement le besoin de télécharger la vidéo et le son du flux réel. Pour maintenir à jour le statut (EN LIGNE ou HORS LIGNE) des chaînes, une connexion websocket est établie pour recevoir des événements sur les flux qui montent ou descendent, ou des mises à jour concernant le nombre actuel de spectateurs.", + "how_it_works_text": "Toutes les ~20 secondes, l'application demande à Twitch une URL vers les données brutes du flux de la chaîne actuellement regardée. Elle récupère ensuite les métadonnées de ce flux de données - ce qui suffit pour faire avancer les drops. Notez que cela contourne complètement le besoin de télécharger la vidéo et le son du flux réel. Pour maintenir à jour le statut (EN LIGNE ou HORS LIGNE) des chaînes, une connexion websocket est établie pour recevoir des événements sur les flux qui montent ou descendent, ou des mises à jour concernant le nombre actuel de spectateurs.", "getting_started": "Premiers pas", "getting_started_text": "1. Connectez-vous à l'application.\n2. Assurez-vous que votre compte Twitch est lié à toutes les campagnes qui vous intéressent.\n3. Si vous voulez simplement miner tout, décochez \"Priorité uniquement\" et appuyez sur \"Recharger\".\n4. Si vous souhaitez miner d'abord certains jeux, utilisez la liste \"Priorité\" pour définir une liste ordonnée des jeux de votre choix. Les jeux en haut de la liste seront tentés d'être minés en premier, avant ceux plus bas dans la liste.\n5. Laissez l'option \"Priorité uniquement\" cochée pour éviter de miner des jeux qui ne sont pas dans la liste de priorité. Ou pas - c'est à vous de décider.\n6. Utilisez la liste \"Exclure\" pour indiquer à l'application les jeux qui ne doivent jamais être minés.\n7. Modifier le contenu de l'une des listes ou changer l'état de l'option \"Priorité uniquement\" nécessite d'appuyer sur \"Recharger\" pour que les changements prennent effet." } diff --git a/lang/Italiano.json b/lang/Italiano.json index 9a5abd9e..8ea7016d 100644 --- a/lang/Italiano.json +++ b/lang/Italiano.json @@ -1,162 +1,164 @@ { - "english_name": "Italian", + "english_name": "Italian", + "status": { + "terminated": "\nApplicazione Terminata.\nChiudi la finestra per uscire dall'applicazione.", + "watching": "Guardando: {channel}", + "goes_online": "{channel} è ONLINE, cambiando...", + "goes_offline": "{channel} è OFFLINE, cambiando...", + "claimed_drop": "Contenuti riscattati: {drop}", + "claimed_points": "Punti bonus riscattati: {points}", + "earned_points": "Punti bonus guadagnati per aver guardato la stream: {points}, totale: {balance}", + "no_channel": "Nessun canale disponibile da guardare. In attesa di un canale ONLINE...", + "no_campaign": "Nessuna campagna attiva per ottenere i premi. In attesa di una campagna attiva..." + }, + "login": { + "unexpected_content": "Tipo di contenuto inaspettato restituito, di solito a causa di un reindirizzamento. Hai bisogno di fare il login per accedere a internet?", + "chrome": { + "startup": "Apertura di Chrome...", + "login_to_complete": "Completa la procedura di login manualmente premendo nuovamente il pulsante Login.", + "no_token": "Nessun token di autorizzazione trovato.", + "closed_window": "La finestra di Chrome è stata chiusa prima che la procedura di login potesse completarsi." + }, + "error_code": "Codice di errore del login: {error_code}", + "incorrect_login_pass": "Nome utente o password errati.", + "incorrect_email_code": "Codice email errato.", + "incorrect_twofa_code": "Codice 2FA errato.", + "email_code_required": "Codice email richiesto. Controlla la tua email.", + "twofa_code_required": "Token 2FA richiesto." + }, + "error": { + "captcha": "Il tuo tentativo di login è stato negato da CAPTCHA.\nRiprova tra 12+ ore.", + "site_down": "Twitch è irraggiungibile, riprovo tra {seconds} secondi...", + "no_connection": "Impossibile connettersi a Twitch, riprovo tra {seconds} secondi..." + }, + "gui": { + "output": "Output", "status": { - "terminated": "\nApplicazione Terminata.\nChiudi la finestra per uscire dall'applicazione.", - "watching": "Guardando: {channel}", - "goes_online": "{channel} è ONLINE, cambiando...", - "goes_offline": "{channel} è OFFLINE, cambiando...", - "claimed_drop": "Contenuti riscattati: {drop}", - "claimed_points": "Punti bonus riscattati: {points}", - "earned_points": "Punti bonus guadagnati per aver guardato la stream: {points}, totale: {balance}", - "no_channel": "Nessun canale disponibile da guardare. In attesa di un canale ONLINE...", - "no_campaign": "Nessuna campagna attiva per ottenere i premi. In attesa di una campagna attiva..." + "name": "Stato", + "idle": "Inattivo", + "exiting": "Uscendo...", + "terminated": "Terminato", + "cleanup": "Pulendo i canali...", + "gathering": "Raccogliendo i canali...", + "switching": "Cambiando canale...", + "fetching_inventory": "Recupero dell'inventario...", + "fetching_campaigns": "Recupero delle campagne...", + "adding_campaigns": "Aggiunta delle campagne all'inventario... {counter}" + }, + "tabs": { + "main": "Principale", + "inventory": "Inventario", + "settings": "Impostazioni", + "help": "Aiuto" + }, + "tray": { + "notification_title": "Premio Ottenuto", + "minimize": "Minimizza nella barra delle applicazioni", + "show": "Mostra", + "quit": "Esci" }, "login": { - "unexpected_content": "Tipo di contenuto inaspettato restituito, di solito a causa di un reindirizzamento. Hai bisogno di fare il login per accedere a internet?", - "chrome": { - "startup": "Apertura di Chrome...", - "login_to_complete": "Completa la procedura di login manualmente premendo nuovamente il pulsante Login.", - "no_token": "Nessun token di autorizzazione trovato.", - "closed_window": "La finestra di Chrome è stata chiusa prima che la procedura di login potesse completarsi." - }, - "error_code": "Codice di errore del login: {error_code}", - "incorrect_login_pass": "Nome utente o password errati.", - "incorrect_email_code": "Codice email errato.", - "incorrect_twofa_code": "Codice 2FA errato.", - "email_code_required": "Codice email richiesto. Controlla la tua email.", - "twofa_code_required": "Token 2FA richiesto." + "name": "Dettagli Login", + "labels": "Stato:\nID Utente:", + "logged_in": "Loggato", + "logged_out": "Non loggato", + "logging_in": "Loggando...", + "required": "Login richiesto", + "request": "Per favore, effettua il login per continuare.", + "username": "Nome utente", + "password": "Password", + "twofa_code": "Codice 2FA (opzionale)", + "button": "Login" + }, + "websocket": { + "name": "Stato del Websocket", + "websocket": "Websocket #{id}:", + "initializing": "Inizializzando...", + "connected": "Connesso", + "disconnected": "Disconnesso", + "connecting": "Connettendo...", + "disconnecting": "Disconnettendo...", + "reconnecting": "Riconnettendo..." + }, + "progress": { + "name": "Progresso della Campagna", + "drop": "Contenuto:", + "game": "Gioco:", + "campaign": "Campagna:", + "remaining": "{time} rimanenti", + "drop_progress": "Progresso:", + "campaign_progress": "Progresso:" + }, + "channels": { + "name": "Canali", + "switch": "Cambia", + "load_points": "Carica Punti", + "online": "ONLINE ✔", + "pending": "OFFLINE ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "Canale", + "status": "Stato", + "game": "Gioco", + "viewers": "Spettatori", + "points": "Punti" + } + }, + "inventory": { + "filter": { + "name": "Filtro", + "show": "Mostra:", + "not_linked": "Non collegato", + "upcoming": "In arrivo", + "expired": "Scaduti", + "excluded": "Esclusi", + "finished": "Finiti", + "refresh": "Aggiorna" + }, + "status": { + "linked": "Collegato ✔", + "not_linked": "Non collegato ❌", + "active": "Attivo ✔", + "upcoming": "In arrivo ⏳", + "expired": "Scaduto ❌", + "claimed": "Riscattato ✔", + "ready_to_claim": "Pronto per essere riscattato ⏳" + }, + "starts": "Inizia: {time}", + "ends": "Finisce: {time}", + "allowed_channels": "Canali consentiti:", + "all_channels": "Tutti", + "and_more": "e altri {amount}...", + "percent_progress": "{percent} di {minutes} minuti", + "minutes_progress": "{minutes} minuti" }, - "error": { - "captcha": "Il tuo tentativo di login è stato negato da CAPTCHA.\nRiprova tra 12+ ore.", - "site_down": "Twitch è irraggiungibile, riprovo tra {seconds} secondi...", - "no_connection": "Impossibile connettersi a Twitch, riprovo tra {seconds} secondi..." + "settings": { + "general": { + "name": "Generale", + "dark_theme": "Tema scuro: ", + "autostart": "Avvio automatico: ", + "tray": "Avvio automatico nella barra delle applicazioni: ", + "tray_notifications": "Notifiche: ", + "priority_only": "Solo priorità: ", + "prioritize_by_ending_soonest": "Dai la priorità in base all'ora di fine: ", + "proxy": "Proxy (richiede il riavvio):" + }, + "game_name": "Nome del gioco", + "priority": "Priorità", + "exclude": "Escludi", + "reload": "Ricarica", + "reload_text": "La maggior parte delle modifiche richiede una ricarica con il botto nqui di fianco per avere un effetto immediato: " }, - "gui": { - "output": "Output", - "status": { - "name": "Stato", - "idle": "Inattivo", - "exiting": "Uscendo...", - "terminated": "Terminato", - "cleanup": "Pulendo i canali...", - "gathering": "Raccogliendo i canali...", - "switching": "Cambiando canale...", - "fetching_inventory": "Recupero dell'inventario...", - "fetching_campaigns": "Recupero delle campagne...", - "adding_campaigns": "Aggiunta delle campagne all'inventario... {counter}" - }, - "tabs": { - "main": "Principale", - "inventory": "Inventario", - "settings": "Impostazioni", - "help": "Aiuto" - }, - "tray": { - "notification_title": "Premio Ottenuto", - "minimize": "Minimizza nella barra delle applicazioni", - "show": "Mostra", - "quit": "Esci" - }, - "login": { - "name": "Dettagli Login", - "labels": "Stato:\nID Utente:", - "logged_in": "Loggato", - "logged_out": "Non loggato", - "logging_in": "Loggando...", - "required": "Login richiesto", - "request": "Per favore, effettua il login per continuare.", - "username": "Nome utente", - "password": "Password", - "twofa_code": "Codice 2FA (opzionale)", - "button": "Login" - }, - "websocket": { - "name": "Stato del Websocket", - "websocket": "Websocket #{id}:", - "initializing": "Inizializzando...", - "connected": "Connesso", - "disconnected": "Disconnesso", - "connecting": "Connettendo...", - "disconnecting": "Disconnettendo...", - "reconnecting": "Riconnettendo..." - }, - "progress": { - "name": "Progresso della Campagna", - "drop": "Contenuto:", - "game": "Gioco:", - "campaign": "Campagna:", - "remaining": "{time} rimanenti", - "drop_progress": "Progresso:", - "campaign_progress": "Progresso:" - }, - "channels": { - "name": "Canali", - "switch": "Cambia", - "load_points": "Carica Punti", - "online": "ONLINE \u2714", - "pending": "OFFLINE \u23f3", - "offline": "OFFLINE \u274c", - "headings": { - "channel": "Canale", - "status": "Stato", - "game": "Gioco", - "viewers": "Spettatori", - "points": "Punti" - } - }, - "inventory": { - "filter": { - "name": "Filtro", - "show": "Mostra:", - "not_linked": "Non collegato", - "upcoming": "In arrivo", - "expired": "Scaduti", - "excluded": "Esclusi", - "finished": "Finiti", - "refresh": "Aggiorna" - }, - "status": { - "linked": "Collegato \u2714", - "not_linked": "Non collegato \u274c", - "active": "Attivo \u2714", - "upcoming": "In arrivo \u23f3", - "expired": "Scaduto \u274c", - "claimed": "Riscattato \u2714", - "ready_to_claim": "Pronto per essere riscattato \u23f3" - }, - "starts": "Inizia: {time}", - "ends": "Finisce: {time}", - "allowed_channels": "Canali consentiti:", - "all_channels": "Tutti", - "and_more": "e altri {amount}...", - "percent_progress": "{percent} di {minutes} minuti", - "minutes_progress": "{minutes} minuti" - }, - "settings": { - "general": { - "name": "Generale", - "autostart": "Avvio automatico: ", - "tray": "Avvio automatico nella barra delle applicazioni: ", - "tray_notifications": "Notifiche: ", - "priority_only": "Solo priorità: ", - "proxy": "Proxy (richiede il riavvio):" - }, - "game_name": "Nome del gioco", - "priority": "Priorità", - "exclude": "Escludi", - "reload": "Ricarica", - "reload_text": "La maggior parte delle modifiche richiede una ricarica con il botto nqui di fianco per avere un effetto immediato: " - }, - "help": { - "links": { - "name": "Link utili", - "inventory": "Vedi l'inventario di Twitch", - "campaigns": "Vedi tutte le campagne e gestisci i collegamenti dell'account" - }, - "how_it_works": "Come funziona", - "how_it_works_text": "Ogni ~60 secondi, l'applicazione invia un evento \"minuto guardato\" al canale che stai guardando - questo è sufficiente per far avanzare il progresso dei drop. Da notare che questo bypassa completamente la necessità di scaricare qualsiasi video o audio della diretta. Per mantenere lo stato (ONLINE o OFFLINE) dei canali aggiornato, c'è una connessione websocket stabilita che riceve eventi sui canali che vanno online o offline, o aggiornamenti riguardanti il numero attuale di spettatori.", - "getting_started": "Per iniziare", - "getting_started_text": "1. Effettua il login nell'applicazione.\n2. Assicurati che il tuo account Twitch sia collegato a tutte le campagne per cui sei interessato a ottenere i drop.\n3. Se sei interessato a ottenere tutto, deseleziona \"Solo priorità\" e premi su \"Ricarica\".\n4. Se vuoi ottenere prima giochi specifici, usa la lista \"Priorità\" per impostare una lista ordinata di giochi a tua scelta. I giochi in cima alla lista verranno ottenuti prima.\n5. Mantieni l'opzione \"Solo priorità\" selezionata, per evitare di ottenere giochi che non sono nella lista delle priorità. Oppure non farlo - dipende da te.\n6. Usa la lista \"Escludi\" per dire all'applicazione quali giochi non devono mai essere ottenuti.\n7. Cambiare il contenuto di una delle liste, o cambiare lo stato dell'opzione \"Solo priorità\", richiede di premere su \"Ricarica\" perché le modifiche abbiano effetto." - } + "help": { + "links": { + "name": "Link utili", + "inventory": "Vedi l'inventario di Twitch", + "campaigns": "Vedi tutte le campagne e gestisci i collegamenti dell'account" + }, + "how_it_works": "Come funziona", + "how_it_works_text": "Circa ogni 20 secondi, l'applicazione chiede a Twitch un URL per il flusso di dati grezzi del canale attualmente guardato. Successivamente, recupera i metadati di questo flusso e ciò è sufficiente per far avanzare il progresso dei drop. Da notare che questo bypassa completamente la necessità di scaricare qualsiasi video o audio della diretta. Per mantenere aggiornato lo stato (ONLINE o OFFLINE) dei canali, viene stabilita una connessione websocket che riceve eventi sui canali che vanno online o offline, oppure aggiornamenti relativi al numero attuale di spettatori.", + "getting_started": "Per iniziare", + "getting_started_text": "1. Effettua il login nell'applicazione.\n2. Assicurati che il tuo account Twitch sia collegato a tutte le campagne per cui sei interessato a ottenere i drop.\n3. Se sei interessato a ottenere tutto, deseleziona \"Solo priorità\" e premi su \"Ricarica\".\n4. Se vuoi ottenere prima giochi specifici, usa la lista \"Priorità\" per impostare una lista ordinata di giochi a tua scelta. I giochi in cima alla lista verranno ottenuti prima.\n5. Mantieni l'opzione \"Solo priorità\" selezionata, per evitare di ottenere giochi che non sono nella lista delle priorità. Oppure non farlo - dipende da te.\n6. Usa la lista \"Escludi\" per dire all'applicazione quali giochi non devono mai essere ottenuti.\n7. Cambiare il contenuto di una delle liste, o cambiare lo stato dell'opzione \"Solo priorità\", richiede di premere su \"Ricarica\" perché le modifiche abbiano effetto." } + } } diff --git a/lang/Polski.json b/lang/Polski.json index 85cfa44e..feded1a7 100644 --- a/lang/Polski.json +++ b/lang/Polski.json @@ -1,162 +1,164 @@ { - "english_name": "Polish", + "english_name": "Polish", + "status": { + "terminated": "\nAplikacja została zatrzymana.\nZamknij okno, aby wyjść z aplikacji.", + "watching": "Oglądam kanał: {channel}", + "goes_online": "Nowy status kanału {channel}: ONLINE, zmieniam...", + "goes_offline": "Nowy status kanału {channel}: OFFLINE, zmieniam...", + "claimed_drop": "Odebrano drop: {drop}", + "claimed_points": "Odebrano punkty: {points}", + "earned_points": "Zdobyto punkty za oglądanie: {points} | Łącznie: {balance}", + "no_channel": "Brak możliwych kanałów do oglądania. Oczekiwanie na nową kampanię...", + "no_campaign": "Brak dostępnych aktywnych kampanii. Oczekiwanie na nową kampanię..." + }, + "login": { + "unexpected_content": "Nieoczekiwany błąd zawartości, zwykle z powodu przekierowania.\nUpewnij się że nie jest wymagane dodatkowe logowanie bądź potwierdzenie dostępu do internetu.", + "chrome": { + "startup": "Uruchamianie Chrome...", + "login_to_complete": "Naciśnij ponownie zaloguj, aby zakończyć proces ręcznego logowania...", + "no_token": "Nie znaleziono tokena autoryzacyjnego.", + "closed_window": "Okno przeglądarki Chrome zostało zamknięte przed zakończeniem procesu logowania." + }, + "error_code": "Kod błędu logowania: {error_code}", + "incorrect_login_pass": "Nieprawidłowa nazwa użytkownika lub hasło.", + "incorrect_email_code": "Nieprawidłowy kod z e-maila.", + "incorrect_twofa_code": "Nieprawidłowy kod 2FA.", + "email_code_required": "Wymagany kod z e-maila.", + "twofa_code_required": "Wymagany token 2FA." + }, + "error": { + "captcha": "Próba logowania została odrzucona przez CAPTCHA.\nProszę spróbować ponownie za co najmniej 12 godzin.", + "site_down": "Strona Twitcha nie jest dostępna. Spróbuj ponownie za {seconds} s....", + "no_connection": "Nie można połączyć się z Twitchem. Spróbuj ponownie za {seconds} s...." + }, + "gui": { + "output": "Dziennik zdarzeń", "status": { - "terminated": "\nAplikacja została zatrzymana.\nZamknij okno, aby wyjść z aplikacji.", - "watching": "Oglądam kanał: {channel}", - "goes_online": "Nowy status kanału {channel}: ONLINE, zmieniam...", - "goes_offline": "Nowy status kanału {channel}: OFFLINE, zmieniam...", - "claimed_drop": "Odebrano drop: {drop}", - "claimed_points": "Odebrano punkty: {points}", - "earned_points": "Zdobyto punkty za oglądanie: {points} | Łącznie: {balance}", - "no_channel": "Brak możliwych kanałów do oglądania. Oczekiwanie na nową kampanię...", - "no_campaign": "Brak dostępnych aktywnych kampanii. Oczekiwanie na nową kampanię..." + "name": "Status", + "idle": "Bezczynność", + "exiting": "Zamykanie...", + "terminated": "Zatrzymano", + "cleanup": "Czyszczenie kanałów...", + "gathering": "Szukanie kanałów...", + "switching": "Zmiana kanałów...", + "fetching_inventory": "Odświeżanie ekwipunku...", + "fetching_campaigns": "Odświeżanie kampanii...", + "adding_campaigns": "Dodawanie kampanii do ekwipunku... {counter}" + }, + "tabs": { + "main": "Główna", + "inventory": "Ekwipunek", + "settings": "Ustawienia", + "help": "Pomoc" + }, + "tray": { + "notification_title": "Drop odebrany", + "minimize": "Zminimalizuj", + "show": "Pokaż", + "quit": "Wyjdź" }, "login": { - "unexpected_content": "Nieoczekiwany błąd zawartości, zwykle z powodu przekierowania.\nUpewnij się że nie jest wymagane dodatkowe logowanie bądź potwierdzenie dostępu do internetu.", - "chrome": { - "startup": "Uruchamianie Chrome...", - "login_to_complete": "Naciśnij ponownie zaloguj, aby zakończyć proces ręcznego logowania...", - "no_token": "Nie znaleziono tokena autoryzacyjnego.", - "closed_window": "Okno przeglądarki Chrome zostało zamknięte przed zakończeniem procesu logowania." - }, - "error_code": "Kod błędu logowania: {error_code}", - "incorrect_login_pass": "Nieprawidłowa nazwa użytkownika lub hasło.", - "incorrect_email_code": "Nieprawidłowy kod z e-maila.", - "incorrect_twofa_code": "Nieprawidłowy kod 2FA.", - "email_code_required": "Wymagany kod z e-maila.", - "twofa_code_required": "Wymagany token 2FA." + "name": "Logowanie", + "labels": "Status:\nIdentyfikator:", + "logged_in": "Zalogowano", + "logged_out": "Wylogowano", + "logging_in": "Logowanie...", + "required": "Wymagane zalogowanie", + "request": "Zaloguj się, by kontynuować.", + "username": "Nazwa użytkownika", + "password": "Hasło", + "twofa_code": "Kod 2FA (opcjonalnie)", + "button": "Zaloguj" + }, + "websocket": { + "name": "Status WebSocket", + "websocket": "WebSocket #{id}:", + "initializing": "Inicjalizacja...", + "connected": "Połączono", + "disconnected": "Rozłączono", + "connecting": "Łączenie...", + "disconnecting": "Rozłączanie...", + "reconnecting": "Ponowne łączenie..." + }, + "progress": { + "name": "Postępy kampanii", + "drop": "Drop:", + "game": "Gra:", + "campaign": "Kampania:", + "remaining": "Pozostało: {time}", + "drop_progress": "Postęp dropu:", + "campaign_progress": "Postęp kampanii:" + }, + "channels": { + "name": "Kanały", + "switch": "Zmień", + "load_points": "Załaduj punkty", + "online": "ONLINE ✔", + "pending": "W TOKU ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "Kanał", + "status": "Status", + "game": "Gra", + "viewers": "Widzowie", + "points": "Punkty" + } + }, + "inventory": { + "filter": { + "name": "Filtr", + "show": "Pokaż:", + "not_linked": "Niepołączone", + "upcoming": "Nadchodzące", + "expired": "Wygasłe", + "excluded": "Wykluczone", + "finished": "Ukończone", + "refresh": "Odśwież" + }, + "status": { + "linked": "Połączono ✔", + "not_linked": "Nie połączono ❌", + "active": "Aktywna ✔", + "upcoming": "Nadchodząca ⏳", + "expired": "Wygasła ❌", + "claimed": "Odebrano ✔", + "ready_to_claim": "Gotowe do odebrania ⏳" + }, + "starts": "Rozpoczęcie: {time}", + "ends": "Koniec: {time}", + "allowed_channels": "Dozwolone kanały:", + "all_channels": "Wszystkie kanały", + "and_more": "i {amount} więcej...", + "percent_progress": "{percent} z {minutes} min.", + "minutes_progress": "{minutes} min." }, - "error": { - "captcha": "Próba logowania została odrzucona przez CAPTCHA.\nProszę spróbować ponownie za co najmniej 12 godzin.", - "site_down": "Strona Twitcha nie jest dostępna. Spróbuj ponownie za {seconds} s....", - "no_connection": "Nie można połączyć się z Twitchem. Spróbuj ponownie za {seconds} s...." + "settings": { + "general": { + "name": "Ogólne", + "dark_theme": "Ciemny motyw:", + "autostart": "Autostart: ", + "tray": "Autostart z zasobnika: ", + "tray_notifications": "Powiadomienia z zasobnika: ", + "priority_only": "Tylko priorytetowe: ", + "prioritize_by_ending_soonest": "Priorytetyzuj według czasu zakończenia:", + "proxy": "Proxy (wymaga restartu):" + }, + "game_name": "Nazwa gry", + "priority": "Priorytety", + "exclude": "Wykluczone", + "reload": "Przeładuj", + "reload_text": "Większość zmian wymaga przeładowania, które natychmiastowo je zastosuje: " }, - "gui": { - "output": "Dziennik zdarzeń", - "status": { - "name": "Status", - "idle": "Bezczynność", - "exiting": "Zamykanie...", - "terminated": "Zatrzymano", - "cleanup": "Czyszczenie kanałów...", - "gathering": "Szukanie kanałów...", - "switching": "Zmiana kanałów...", - "fetching_inventory": "Odświeżanie ekwipunku...", - "fetching_campaigns": "Odświeżanie kampanii...", - "adding_campaigns": "Dodawanie kampanii do ekwipunku... {counter}" - }, - "tabs": { - "main": "Główna", - "inventory": "Ekwipunek", - "settings": "Ustawienia", - "help": "Pomoc" - }, - "tray": { - "notification_title": "Drop odebrany", - "minimize": "Zminimalizuj", - "show": "Pokaż", - "quit": "Wyjdź" - }, - "login": { - "name": "Logowanie", - "labels": "Status:\nIdentyfikator:", - "logged_in": "Zalogowano", - "logged_out": "Wylogowano", - "logging_in": "Logowanie...", - "required": "Wymagane zalogowanie", - "request": "Zaloguj się, by kontynuować.", - "username": "Nazwa użytkownika", - "password": "Hasło", - "twofa_code": "Kod 2FA (opcjonalnie)", - "button": "Zaloguj" - }, - "websocket": { - "name": "Status WebSocket", - "websocket": "WebSocket #{id}:", - "initializing": "Inicjalizacja...", - "connected": "Połączono", - "disconnected": "Rozłączono", - "connecting": "Łączenie...", - "disconnecting": "Rozłączanie...", - "reconnecting": "Ponowne łączenie..." - }, - "progress": { - "name": "Postępy kampanii", - "drop": "Drop:", - "game": "Gra:", - "campaign": "Kampania:", - "remaining": "Pozostało: {time}", - "drop_progress": "Postęp dropu:", - "campaign_progress": "Postęp kampanii:" - }, - "channels": { - "name": "Kanały", - "switch": "Zmień", - "load_points": "Załaduj punkty", - "online": "ONLINE ✔", - "pending": "W TOKU ⏳", - "offline": "OFFLINE ❌", - "headings": { - "channel": "Kanał", - "status": "Status", - "game": "Gra", - "viewers": "Widzowie", - "points": "Punkty" - } - }, - "inventory": { - "filter": { - "name": "Filtr", - "show": "Pokaż:", - "not_linked": "Niepołączone", - "upcoming": "Nadchodzące", - "expired": "Wygasłe", - "excluded": "Wykluczone", - "finished": "Ukończone", - "refresh": "Odśwież" - }, - "status": { - "linked": "Połączono ✔", - "not_linked": "Nie połączono ❌", - "active": "Aktywna ✔", - "upcoming": "Nadchodząca ⏳", - "expired": "Wygasła ❌", - "claimed": "Odebrano ✔", - "ready_to_claim": "Gotowe do odebrania ⏳" - }, - "starts": "Rozpoczęcie: {time}", - "ends": "Koniec: {time}", - "allowed_channels": "Dozwolone kanały:", - "all_channels": "Wszystkie kanały", - "and_more": "i {amount} więcej...", - "percent_progress": "{percent} z {minutes} min.", - "minutes_progress": "{minutes} min." - }, - "settings": { - "general": { - "name": "Ogólne", - "autostart": "Autostart: ", - "tray": "Autostart z zasobnika: ", - "tray_notifications": "Powiadomienia z zasobnika: ", - "priority_only": "Tylko priorytetowe: ", - "proxy": "Proxy (wymaga restartu):" - }, - "game_name": "Nazwa gry", - "priority": "Priorytety", - "exclude": "Wykluczone", - "reload": "Przeładuj", - "reload_text": "Większość zmian wymaga przeładowania, które natychmiastowo je zastosuje: " - }, - "help": { - "links": { - "name": "Pomocne linki", - "inventory": "Zobacz swój ekwipunek na Twitchu", - "campaigns": "Zobacz wszystkie kampanie na Twitchu" - }, - "how_it_works": "Jak to działa?", - "how_it_works_text": "Co ~60 sekund aplikacja wysyła zdarzenie „obejrzana minuta” do kanału, który jest aktualnie oglądany - to wystarczy, aby ukończyć dropienie. Zauważ, że w ten sposób możesz całkowicie pominąć konieczność pobierania rzeczywistego strumienia wideo i dźwięku. Do utrzymania statusu ONLINE lub OFFLINE kanałów używane jest połączenie WebSocket, które odbiera zdarzenia o zmianie statusu kanałów oraz aktualizuje aktualną ilość widzów.", - "getting_started": "Pierwsze kroki", - "getting_started_text": "1. Zaloguj się do aplikacji.\n2. Upewnij się, że twoje konto Twitch jest połączone ze wszystkimi kampaniami, z których chcesz dropić.\n3. Odznacz opcję „Tylko priorytetowe” i kliknij „Przeładuj”, jeśli chcesz rozpocząć dropienie ze wszystkich aktywnych kampanii.\n4. Użyj listy „Priorytety”, aby wybrać uporządkowaną listę gier, z których chcesz otrzymać dropy. Gry z górnej części listy będą miały większy priorytet dropienia niż te niżej na liście.\n5. Zaznacz opcję „Tylko priorytetowe”, aby wykluczyć z dropienia gry, które nie są na liście priorytetowej.\n6. Użyj listy „Wykluczone”, aby wskazać aplikacji gry, z których przedmioty nigdy nie powinny być dropione.\n7. Zmiana zawartości list lub opcji „Tylko priorytetowe” wymaga kliknięcia „Przeładuj”, aby aplikacja mogła zastosować wprowadzone zmiany." - } + "help": { + "links": { + "name": "Pomocne linki", + "inventory": "Zobacz swój ekwipunek na Twitchu", + "campaigns": "Zobacz wszystkie kampanie na Twitchu" + }, + "how_it_works": "Jak to działa?", + "how_it_works_text": "Co ~60 sekund aplikacja wysyła zdarzenie „obejrzana minuta” do kanału, który jest aktualnie oglądany - to wystarczy, aby ukończyć dropienie. Zauważ, że w ten sposób możesz całkowicie pominąć konieczność pobierania rzeczywistego strumienia wideo i dźwięku. Do utrzymania statusu ONLINE lub OFFLINE kanałów używane jest połączenie WebSocket, które odbiera zdarzenia o zmianie statusu kanałów oraz aktualizuje aktualną ilość widzów.", + "getting_started": "Pierwsze kroki", + "getting_started_text": "1. Zaloguj się do aplikacji.\n2. Upewnij się, że twoje konto Twitch jest połączone ze wszystkimi kampaniami, z których chcesz dropić.\n3. Odznacz opcję „Tylko priorytetowe” i kliknij „Przeładuj”, jeśli chcesz rozpocząć dropienie ze wszystkich aktywnych kampanii.\n4. Użyj listy „Priorytety”, aby wybrać uporządkowaną listę gier, z których chcesz otrzymać dropy. Gry z górnej części listy będą miały większy priorytet dropienia niż te niżej na liście.\n5. Zaznacz opcję „Tylko priorytetowe”, aby wykluczyć z dropienia gry, które nie są na liście priorytetowej.\n6. Użyj listy „Wykluczone”, aby wskazać aplikacji gry, z których przedmioty nigdy nie powinny być dropione.\n7. Zmiana zawartości list lub opcji „Tylko priorytetowe” wymaga kliknięcia „Przeładuj”, aby aplikacja mogła zastosować wprowadzone zmiany." } + } } diff --git "a/lang/T\303\274rk\303\247e.json" "b/lang/T\303\274rk\303\247e.json" index f4c271cb..9bede2ac 100644 --- "a/lang/T\303\274rk\303\247e.json" +++ "b/lang/T\303\274rk\303\247e.json" @@ -1,161 +1,164 @@ { - "english_name": "Turkish", + "english_name": "Turkish", + "status": { + "terminated": "\nUygulama durduruldu.\nUygulamadan çıkmak için pencereyi kapatın", + "watching": "{channel} izleniyor", + "goes_online": "{channel} ÇEVRİM İÇİ oldu, geçiş yapılıyor...", + "goes_offline": "{channel} ÇEVRİM DIŞI oldu, geçiş yapılıyor...", + "claimed_drop": "Alınan ödül: {drop}", + "claimed_points": "Kazanılan bonus kanal puanları: {points}", + "earned_points": "İzleme karşılığında kazanılan kanal puanları: {points} | Toplam: {balance}", + "no_channel": "İzlenebilecek kanal yok. ÇEVRİM İÇİ kanal bekleniyor...", + "no_campaign": "Ödül madenciliği için aktif kampanya yok. Aktif bir kampanya bekleniyor..." + }, + "login": { + "unexpected_content": "Beklenmeyen içerik türü döndürüldü, genellikle yeniden yönlendirilme nedeniyle. İnternet erişimi için giriş yapmanız gerekiyor mu?", + "chrome": { + "startup": "Tarayıcı Açılıyor...", + "login_to_complete": "Oturum aç düğmesine tekrar basarak oturum açma işlemini kendiniz tamamlayın.", + "no_token": "Yetkilendirme anahtarı bulunamadı.", + "closed_window": "Oturum açma işlemi tamamlanamadan tarayıcı penceresi kapatıldı." + }, + "error_code": "Oturum açma hatası kodu: {error_code}", + "incorrect_login_pass": "Yanlış kullanıcı adı veya şifre.", + "incorrect_email_code": "Yanlış e-posta kodu.", + "incorrect_twofa_code": "Yanlış 2FA kodu.", + "email_code_required": "E-posta kodu gerekli. Lütfen e-postanızı kontrol edin.", + "twofa_code_required": "2FA kodu gerekli." + }, + "error": { + "captcha": "Giriş denemeniz CAPTCHA tarafından reddedildi.\nLütfen en az 12 saat sonra tekrar deneyin.", + "site_down": "Twitch kapalı, {seconds} saniye içinde tekrar denenecek...", + "no_connection": "Twitch'e bağlanılamıyor. {seconds} saniye içinde tekrar deneniyor..." + }, + "gui": { + "output": "Çıktı", "status": { - "terminated": "\nUygulama durduruldu.\nUygulamadan çıkmak için pencereyi kapatın", - "watching": "{channel} izleniyor", - "goes_online": "{channel} ÇEVRİMİÇİ oldu, geçiş yapın...", - "goes_offline": "{channel} ÇEVRİMDIŞI duruma geçti, geçiş yapın...", - "claimed_drop": "Alınan drop: {drop}", - "claimed_points": "Kazanılan kanal puanları: {points}", - "earned_points": "İzleme karşılığında kazanılan kanal puanları: {points} | Toplam: {balance}", - "no_channel": "Çevrimiçi katılımcı kanal yok. Kanallar bekleniyor...", - "no_campaign": "Etkin kampanya yok. Yeni kampanya bekleniyor..." + "name": "Durum", + "idle": "Boşta", + "exiting": "Çıkılıyor...", + "terminated": "Sonlandırıldı", + "cleanup": " Kanallar temizleniyor...", + "gathering": " Kanallar toplanıyor...", + "switching": "Kanal değiştiriliyor...", + "fetching_inventory": "Envanter getiriliyor...", + "fetching_campaigns": "Kampanyalar getiriliyor...", + "adding_campaigns": "Kampanyalar envantere ekleniyor... {counter}" + }, + "tabs": { + "main": "Ana Sayfa", + "inventory": "Envanter", + "settings": "Ayarlar", + "help": "Yardım" + }, + "tray": { + "notification_title": "Ödül alındı", + "minimize": "Sistem Tepsisine Küçült", + "show": "Göster", + "quit": "Çık" }, "login": { - "chrome": { - "startup": "Chrome'u Başlat...", - "login_to_complete": "Oturum açma işlemini manuel olarak tamamlamak için tekrar Oturum Aç'a basın.", - "no_token": "Yetkilendirme belirteci bulunamadı.", - "closed_window": "Oturum açma işlemi tamamlanamadan Chrome penceresi kapandı." - }, - "error_code": "Giriş Hata Kodu: {error_code}", - "unexpected_content": "Genellikle bir yönlendirme nedeniyle beklenmeyen içerik türü döndürüldü.\nİnternete erişmek için oturum açmanız gerekiyor mu?", - "incorrect_login_pass": "Yanlış kullanıcı adı veya şifre.", - "incorrect_email_code": "Yanlış e-posta kodu.", - "incorrect_twofa_code": "Yanlış 2FA kodu.", - "email_code_required": "E-posta kodu gerekli. Lütfen e-postayı kontrol edin.", - "twofa_code_required": "2FA belirteci gerekli." + "name": "Giriş Kısmı", + "labels": "Durum:\nKullanıcı ID:", + "logged_in": "Giriş Yapıldı", + "logged_out": "Çıkış Yapıldı", + "logging_in": "Giriş yapılıyor...", + "required": "Oturum açmak gerekli", + "request": "Devam etmek için lütfen giriş yapınız.", + "username": "Kullanıcı Adı", + "password": "Parola", + "twofa_code": "2FA kodu (isteğe bağlı)", + "button": "Giriş yap" + }, + "websocket": { + "name": "WebSocket Durumu", + "websocket": "WebSocket #{id}:", + "initializing": "Başlatılıyor...", + "connected": "Bağlandı", + "disconnected": "Bağlantı koptu", + "connecting": "Bağlanıyor...", + "disconnecting": "Bağlantı kesiliyor...", + "reconnecting": "Yeniden bağlanılıyor..." + }, + "progress": { + "name": "Ödül İlerlemesi", + "drop": "Ödül:", + "game": "Oyun:", + "campaign": "Kampanya:", + "remaining": "{time} geriye kalan", + "drop_progress": "İlerleme:", + "campaign_progress": "İlerleme:" + }, + "channels": { + "name": "Kanallar", + "switch": "Değiştir", + "load_points": "Puanları Yükle", + "online": "ÇEVRİM İÇİ ✔", + "pending": "ÇEVRİM DIŞI⏳", + "offline": "ÇEVRİM DIŞI ❌", + "headings": { + "channel": "Kanal", + "status": "Durum", + "game": "Oyun", + "viewers": "İzleyici", + "points": "Puan" + } + }, + "inventory": { + "filter": { + "name": "Filtre", + "show": "Göster:", + "not_linked": "Bağlantılı değil", + "upcoming": "Gelecekler", + "expired": "Süresi dolanlar", + "excluded": "Hariç tutulanlar", + "finished": "Bitenler", + "refresh": "Yenile" + }, + "status": { + "linked": "Bağlantılı ✔", + "not_linked": "Bağlantılı değil ❌", + "active": "Aktif ✔", + "upcoming": "Gelecek ⏳", + "expired": "Süresi dolmuş ❌", + "claimed": "Alındı ​​✔", + "ready_to_claim": "Almaya hazır ⏳" + }, + "starts": "Başlangıç: {time}", + "ends": "Bitiş: {time}", + "allowed_channels": "Katılan Kanallar:", + "all_channels": "Tüm Kanallar", + "and_more": "ve {amount} diğer...", + "percent_progress": "{percent} {minutes} dakika", + "minutes_progress": "{minutes} dakika" }, - "error": { - "captcha": "Giriş girişimi CAPTCHA tarafından reddedildi.\nLütfen en az 12 saat içinde tekrar deneyin.", - "site_down": "cadı ulaşılmaz. {seconds} saniye içinde tekrar deneniyor...", - "no_connection": "Twitch'e bağlanılamıyor. {seconds} saniye içinde tekrar deneniyor..." + "settings": { + "general": { + "name": "Genel", + "dark_theme": "Karanlık tema:", + "autostart": "Otomatik başlat: ", + "tray": "Sistem tepsisine otomatik başlat: ", + "tray_notifications": "Bildirim gönder: ", + "priority_only": "Öncelik sıralamasına göre: ", + "prioritize_by_ending_soonest": "En kısa sürede biteceklere öncelik ver:", + "proxy": "Proxy (Yeniden başlatma gerektirir):" + }, + "game_name": "Oyun ismi", + "priority": "Öncelik Sırası", + "exclude": "Hariç Tutulacaklar", + "reload": "Yeniden Yükle", + "reload_text": "Değişikliklerin uygulanabilmesi için yeniden yükle tuşuna basılması lazım:" }, - "gui": { - "output": "Protokoll", - "status": { - "name": "Durum", - "idle": "Boşta", - "exiting": "Çıkış...", - "terminated": "Sonlandırıldı", - "cleanup": "Kanalları temizle..", - "gathering": "Kanalları toplama...", - "switching": "Kanal değiştiriliyor...", - "fetching_inventory": "Envanter getiriliyor...", - "fetching_campaigns": "Kampanyalar getiriliyor...", - "adding_campaigns": "Kampanyaları envantere ekle... {counter}" - }, - "tabs": { - "main": "Anasayfa", - "inventory": "Envanter", - "settings": "Ayarlar", - "help": "Yardım" - }, - "tray": { - "notification_title": "Drop alındı", - "minimize": "Sistem tepsisine küçült", - "show": "Göster", - "quit": "Çık" - }, - "login": { - "name": "Giriş Yap", - "labels": "Durum:\nKullanıcı ID:", - "logged_in": "Giriş Yapıldı", - "logged_out": "Çıkış Yapıldı", - "logging_in": "Kayıt Ol...", - "required": "Kaydolmak gerekiyor", - "request": "Devam etmek için lütfen giriş yapınız.", - "username": "Kullanıcı Adı", - "password": "Parola", - "twofa_code": "2FA Kodu (opsyonel)", - "button": "Kayıt Ol" - }, - "websocket": { - "name": "WebSocket Status", - "websocket": "WebSocket #{id}:", - "initializing": "Başlat...", - "connected": "Bağlandı", - "disconnected": "Bağlantı koptu", - "connecting": "Bağlanıyor...", - "disconnecting": "Bağlantı kesiliyor...", - "reconnecting": "Yeniden bağlanılıyor..." - }, - "progress": { - "name": "Drop İlerlemesi", - "drop": "Drop:", - "game": "Oyun:", - "campaign": "Kampanya:", - "remaining": "{time} geriye kalan", - "drop_progress": "İlerleme:", - "campaign_progress": "İlerleme:" - }, - "channels": { - "name": "Kanallar", - "switch": "Değiştir", - "load_points": "Puanları Yükle", - "online": "ONLINE ✔", - "pending": "OFFLINE ⏳", - "offline": "OFFLINE ❌", - "headings": { - "channel": "Kanal", - "status": "Durum", - "game": "Oyun", - "viewers": "İzleyici", - "points": "Puan" - } - }, - "inventory": { - "filter": { - "name": "Filtre", - "show": "Dava etmek:", - "not_linked": "Bağlantılı değil", - "upcoming": "Gelecek", - "expired": "Süresi doldu", - "excluded": "Hariç tutuldu", - "finished": "Aldı", - "refresh": "Güncellemek için" - }, - "status": { - "linked": "Bağlantılı ✔", - "not_linked": "Bağlantılı değil ❌", - "active": "Aktif ✔", - "upcoming": "Gelecek ⏳", - "expired": "Süresi dolmuş ❌", - "claimed": "Alındı ​​✔", - "ready_to_claim": "Almaya hazır ⏳" - }, - "starts": "Başladı: {time}", - "ends": "Bitiş: {time}", - "allowed_channels": "Katılan Kanallar:", - "all_channels": "Tüm Kanallar", - "and_more": "ve {amount} diğer...", - "percent_progress": "{percent} {minutes} dakika", - "minutes_progress": "{minutes} dakika" - }, - "settings": { - "general": { - "name": "Genel", - "autostart": "Otomatik başlatma: ", - "tray": "Sistem tepsisine otomatik başlatma: ", - "priority_only": "Yalnızca öncelik: ", - "proxy": "Proxy (Yeniden başlatma gerektirir):" - }, - "game_name": "Oyun", - "priority": "Öncelik", - "exclude": "Hariç tut", - "reload": "Tekrar yükle", - "reload_text": "Değişikliklerin çoğu, hemen yürürlüğe girmesi için yeniden yükleme gerektirir: " - }, - "help": { - "links": { - "name": "Faydalı Bağlantılar", - "inventory": "Twitch Envanterini Görüntüle", - "campaigns": "Tüm Twitch Kampanyalarını Görüntüle" - }, - "how_it_works": "Nasıl çalışır", - "how_it_works_text": "Uygulama, her ~60 saniyede bir \"izlenen dakika\" olayını o anda izlenmekte olan kanala gönderir.\nBu, düşüşü ileri götürmek için yeterlidir. Bu şekilde, indirmeye gerek yoktur akış sağlar ve bant genişliğinden tasarruf sağlar.\nKanalların çevrimiçi veya çevrimdışı durumunu güncel tutmak için, kanalların durumunu kontrol eden\nbir websocket bağlantısı kurulur.", - "getting_started": "Başlarken", - "getting_started_text": "• Uygulamada oturum açın.\n• Twitch hesabının ilgilendiğiniz tüm kampanyalara bağlı olduğundan emin olun.\n• Tüm ödüllerin işlenmesini istiyorsanız, \"Yalnızca öncelikli \" seçeneğinin işaretini kaldırın ve \"Yeniden Yükle\"ye basın.\n• Yalnızca belirli oyunların dikkate alınmasını istiyorsanız, seçimi oyuna göre daraltmak için \"Öncelik\" listesini kullanın.\n• Liste yukarıdan aşağıya doğru öncelik sırasına göre sıralanır. n• \"Yalnızca öncelik\" seçeneği, öncelik listesinde olmayan oyunların işlenmesini engeller.\n• \"Hariç tut\" listesi ile, asla olması gerektiği düşünülmeyecek oyunların filtrelenmesi mümkündür.\n• Listeler veya seçenekler özelleştirilmişse, değişikliklerin geçerli olması için \"Yeniden Yükle\"ye basılmalıdır." - } + "help": { + "links": { + "name": "Faydalı Bağlantılar", + "inventory": "Twitch Envanterini Görüntüle", + "campaigns": "Tüm Twitch Kampanyalarını Görüntüle" + }, + "how_it_works": "Nasıl çalışır", + "how_it_works_text": "Uygulama, her 20 saniyede bir Twitch'ten o anda izlenmekte olan kanalın ham akış verilerine ait bir URL ister. Daha sonra bu veri akışının meta verilerini alır bu ödülleri ilerletmek için yeterlidir. Bu herhangi bir video ve sesi indirme ihtiyacını tamamen atlar. Kanalların durumunu (Çevrim içi veya Çevrim dışı) güncel tutmak için, akışların yukarı veya aşağı gitmesiyle ilgili olayları veya mevcut izleyici miktarıyla ilgili güncellemeleri alan bir websocket bağlantısı kurulmuştur.", + "getting_started": "Başlarken", + "getting_started_text": "1. Uygulamaya giriş yapın.\n2. Twitch hesabınızın madencilikle ilgilendiğiniz tüm kampanyalara bağlı olduğundan emin olun.\n3. Her şeyi madencilikle ilgileniyorsanız, “Yalnızca öncelikli” seçeneğinin işaretini kaldırın ve “Yeniden Yükle” tuşuna basın.\n4. Önce belirli oyunların madenciliğini yapmak istiyorsanız, seçtiğiniz oyunların sıralı bir listesini oluşturmak için “Öncelik” listesini kullanın. Listenin en üstündeki oyunlar, listenin altındakilerden önce çıkarılmaya çalışılacaktır.\n5. Öncelik listesinde olmayan oyunların madenciliğini önlemek için “Yalnızca öncelik” seçeneğini işaretli tutun. Ya da yapmayın , bu size kalmış.\n6. Uygulamaya hangi oyunların asla madenciliğinin yapılmaması gerektiğini söylemek için “Hariç tut” listesini kullanın.\n7. Listelerden herhangi birinin içeriğini değiştirmek veya “Yalnızca öncelik” seçeneğinin durumunu değiştirmek, değişikliklerin etkili olması için “Yeniden Yükle” düğmesine basmanızı gerektirir." } + } } diff --git "a/lang/\304\214e\305\241tina.json" "b/lang/\304\214e\305\241tina.json" index a07bb937..640c31b3 100644 --- "a/lang/\304\214e\305\241tina.json" +++ "b/lang/\304\214e\305\241tina.json" @@ -1,154 +1,164 @@ { - "english_name": "Czech", + "english_name": "Czech", + "status": { + "terminated": "\nAplikace byla ukončena.", + "watching": "Sledování kanálu: {channel}", + "goes_online": "Kanál {channel} je online, přepínám...", + "goes_offline": "Kanál {channel} je offline, přepínám na další...", + "claimed_drop": "Drop vyzvednut: {drop}", + "claimed_points": "Vyzvednuto {points} bodů", + "earned_points": "Získáno {points} bodů za sledování. Celkem: {balance}", + "no_channel": "Žádný kanál není dostupný, čekání na další...", + "no_campaign": "Žádné dropy k dispozici, čekání na další dostupné dropy..." + }, + "login": { + "unexpected_content": "Chyba při přesměrování. Nepoužíváte VPN?", + "chrome": { + "startup": "Otevírá se Chrome...", + "login_to_complete": "Automaticky dokončete proces přihlášení opětovným kliknutím na tlačítko přihlásit.", + "no_token": "Nebyl nalezen žádný autorizační token.", + "closed_window": "Okno Chrome bylo zavřeno před dokončním procesu přihlášení." + }, + "error_code": "Chyba přihlášení: {error_code}", + "incorrect_login_pass": "Nesprávné uživatelské jméno nebo heslo.", + "incorrect_email_code": "Nesprávný E-Mail kód.", + "incorrect_twofa_code": "Nesprávný dvoufaktorový token", + "email_code_required": "K přihlášení je vyžadován kód který byl zaslán na váš E-Mail.", + "twofa_code_required": "K přihlášení je vyžadován dvoufaktorový kód." + }, + "error": { + "captcha": "Vaše připojení bylo zamítnuto systémem přihlásit.CAPTCHA, zkuste to znovu za 12 hodin.", + "site_down": "Služba Twitch je nedostupná,zkuste to znovu za {seconds} sekund...", + "no_connection": "Nelze se připojit k službe Twitch, zkuste to znovu za {seconds}..." + }, + "gui": { + "output": "Výstup", "status": { - "terminated": "\nAplikace byla ukončena.", - "watching": "Sledování kanálu: {channel}", - "goes_online": "Kanál {channel} je online, přepínám...", - "goes_offline": "Kanál {channel} je offline, přepínám na další...", - "claimed_drop": "Drop vyzvednut: {drop}", - "claimed_points": "Vyzvednuto {points} bodů", - "earned_points": "Získáno {points} bodů za sledování. Celkem: {balance}", - "no_channel": "Žádný kanál není dostupný, čekání na další...", - "no_campaign": "Žádné dropy k dispozici, čekání na další dostupné dropy..." + "name": "Status", + "idle": "Dokončeno načítání", + "exiting": "Ukončování...", + "terminated": "Aplikace ukončena", + "cleanup": "Čištění...", + "gathering": "Vyhledávání dostupného živého kanálu...", + "switching": "Přepínám mezi kanály...", + "fetching_inventory": "Načítání inventáře...", + "fetching_campaigns": "Načítání dropů...", + "adding_campaigns": "Přidávám dropy... {counter}" + }, + "tabs": { + "main": "Hlavní Panel", + "inventory": "Inventář", + "settings": "Nastavení", + "help": "Nápověda" + }, + "tray": { + "notification_title": "Začít sbírat dropy", + "minimize": "Minimalizovat", + "show": "Zobrazit", + "quit": "Ukončit" }, "login": { - "unexpected_content": "Chyba při přesměrování. Nepoužíváte VPN?", - "incorrect_login_pass": "Nesprávné přihlašení.", - "incorrect_email_code": "Nesprávný E-Mail kód.", - "incorrect_twofa_code": "Nesprávný dvoufaktorový token", - "email_code_required": "K přihlášení je vyžadován kód který byl zaslán na váš E-Mail.", - "twofa_code_required": "K přihlášení je vyžadován dvoufaktorový kód." + "name": "Přihlášení k službě Twitch", + "labels": "Uživatelské ID:", + "logged_in": "Přihlášeno", + "logged_out": "Odhlášeno", + "logging_in": "Přihlašování...", + "required": "Potřebujete se nejdříve přihlásit", + "request": "Pro přístup je potřeba přihlášení", + "username": "Uživatelské Jméno", + "password": "Heslo", + "twofa_code": "2FA Kód", + "button": "Přihlásit se" + }, + "websocket": { + "name": "Status Připojení Síťového Protokolu", + "websocket": "Websocket #{id}:", + "initializing": "Načítání", + "connected": "Připojeno", + "disconnected": "Odpojeno", + "connecting": "Připojování...", + "disconnecting": "Odpojování...", + "reconnecting": "Přepojování..." + }, + "progress": { + "name": "Průběh Dropu", + "drop": "Drop Odměny:", + "game": "Hra:", + "campaign": "Kampaň:", + "remaining": "Zbývá {time}", + "drop_progress": "Průběh dropu:", + "campaign_progress": "Průběh kampaňe:" + }, + "channels": { + "name": "Název", + "switch": "Přepnout", + "load_points": "Načíst body", + "online": "ONLINE ✔", + "pending": "PRŮBĚH ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "Kanál", + "status": "Status", + "game": "Hra", + "viewers": "Diváci", + "points": "Body" + } + }, + "inventory": { + "filter": { + "name": "Filtr", + "show": "Drop:", + "not_linked": "Nepropojeno", + "upcoming": "Nadcházející", + "expired": "Ukončeno", + "excluded": "Vynecháno", + "finished": "Dokončeno", + "refresh": "Obnovit" + }, + "status": { + "linked": "ŽIVĚ ✔", + "not_linked": "Zatím nejsou dostupné žádné kanály ❌", + "active": "ŽIVĚ ✔", + "upcoming": "Nadcházející ⏳", + "expired": "Ukončeno ❌", + "claimed": "Vyzvednuto ✔", + "ready_to_claim": "Připraveno k vyzvednutí ⏳" + }, + "starts": "Začíná: {time}", + "ends": "Začíná: {time}", + "allowed_channels": "Povolené kanály:", + "all_channels": "Všechny kanály", + "and_more": "Je tu {amount} ...", + "percent_progress": "{minutes} minut {percent}", + "minutes_progress": "{minutes} minut" }, - "error": { - "captcha": "Vaše připojení bylo zamítnuto službou Twitch, zkuste to znovu za 12 hodin.", - "site_down": "Služba Twitch je nedostupná,zkuste to znovu za {seconds} sekund...", - "no_connection": "Nelze se připojit k službe Twitch, zkuste to znovu za {seconds}..." + "settings": { + "general": { + "name": "Nastavení", + "dark_theme": "Tmavý vzhled: ", + "autostart": "Automatické spuštění: ", + "tray": "Automaticky spusti minimalizovaně: ", + "tray_notifications": "Oznámení v systémové liště:", + "priority_only": "Pouze prioritní: ", + "prioritize_by_ending_soonest": "Upřednostnit kampaně podle data ukončení:", + "proxy": "Proxy:" + }, + "game_name": "Název Hry", + "priority": "Priorita", + "exclude": "Vynechat", + "reload": "Obnovit", + "reload_text": "Většina změn vyžaduje restart aplikace nebo obnovení: " }, - "gui": { - "output": "Výstup", - "status": { - "name": "Status", - "idle": "Dokončeno načítání", - "exiting": "Ukončování...", - "terminated": "Aplikace ukončena", - "cleanup": "Čištění...", - "gathering": "Vyhledávání dostupného živého kanálu...", - "switching": "Přepínám mezi kanály...", - "fetching_inventory": "Načítání inventáře...", - "fetching_campaigns": "Načítání dropů...", - "adding_campaigns": "Přidávám dropy... {counter}" - }, - "tabs": { - "main": "Hlavní Panel", - "inventory": "Inventář", - "settings": "Nastavení", - "help": "Nápověda" - }, - "tray": { - "notification_title": "Začít sbírat dropy", - "minimize": "Minimalizovat", - "show": "Zobrazit", - "quit": "Ukončit" - }, - "login": { - "name": "Přihlášení k službě Twitch", - "labels": "Uživatelské ID:", - "logged_in": "Přihlášeno", - "logged_out": "Odhlášeno", - "logging_in": "Přihlašování...", - "required": "Potřebujete se nejdříve přihlásit", - "request": "Pro přístup je potřeba přihlášení", - "username": "Uživatelské Jméno", - "password": "Heslo", - "twofa_code": "2FA Kód", - "button": "Přihlásit se" - }, - "websocket": { - "name": "Status Připojení Síťového Protokolu", - "websocket": "Websocket #{id}:", - "initializing": "Načítání", - "connected": "Připojeno", - "disconnected": "Odpojeno", - "connecting": "Připojování...", - "disconnecting": "Odpojování...", - "reconnecting": "Přepojování..." - }, - "progress": { - "name": "Průběh Dropu", - "drop": "Drop Odměny:", - "game": "Hra:", - "campaign": "Kampaň:", - "remaining": "Zbývá {time}", - "drop_progress": "Průběh dropu:", - "campaign_progress": "Průběh kampaňe:" - }, - "channels": { - "name": "Název", - "switch": "Přepnout", - "load_points": "Načíst body", - "online": "ONLINE \u2714", - "pending": "PRŮBĚH \u23f3", - "offline": "OFFLINE \u274c", - "headings": { - "channel": "Kanál", - "game": "Hra", - "points": "Body", - "status": "Status", - "viewers": "Diváci" - } - }, - "inventory": { - "filter": { - "name": "Filtr", - "show": "Drop:", - "not_linked": "Nepropojeno", - "expired": "Ukončeno", - "excluded": "Vynecháno", - "upcoming": "Nadcházející", - "finished": "Dokončeno", - "refresh": "Obnovit" - }, - "status": { - "linked": "ŽIVĚ \u2714", - "not_linked": "Zatím nejsou dostupné žádné kanály \u274c", - "active": "ŽIVĚ \u2714", - "upcoming": "Nadcházející \u23f3", - "expired": "Ukončeno \u274c", - "claimed": "Vyzvednuto \u2714", - "ready_to_claim": "Připraveno k vyzvednutí \u23f3" - }, - "starts": "Začíná: {time}", - "ends": "Začíná: {time}", - "allowed_channels": "Povolené kanály:", - "all_channels": "Všechny kanály", - "and_more": "Je tu {amount} ...", - "percent_progress": "{minutes} minut {percent}", - "minutes_progress": "{minutes} minut" - }, - "settings": { - "general": { - "name": "Nastavení", - "autostart": "Automatické spuštění: ", - "tray": "Automaticky spusti minimalizovaně: ", - "priority_only": "Pouze prioritní: ", - "proxy": "Proxy:" - }, - "game_name": "Název Hry", - "priority": "Priorita", - "exclude": "Vynechat", - "reload": "Obnovit", - "reload_text": "Většina změn vyžaduje restart aplikace nebo obnovení: " - }, - "help": { - "links": { - "name": "Nápověda", - "inventory": "Zobrazit Twitch Inventář", - "campaigns": "Zobrazit všechny kampaňe a spravovat propojené účty" - }, - "how_it_works": "Jak to funguje", - "how_it_works_text": "Každých ~60 sekund aplikace odešle událost 'sledované minuty' na aktuálně sledovaný kanál - to stačí k posunu umístění. Všimněte si, že tímto způsobem zcela odpadá nutnost stahovat skutečné streamované video a zvuk. Aby byl stav kanálu (online nebo offline) stále aktuální, je navázáno spojení přes websocket, které přijímá události o spuštění nebo vypnutí streamů nebo aktualizace o aktuálním počtu diváků.", - "getting_started": "Jak začít", - "getting_started_text": "1. Přihlaste se do aplikace. \n2. Ujistěte se, že je váš účet Twitch spojen se všemi reklamními sériemi, které chcete těžit. \n3. Pokud chcete klepnout pouze na veškerý obsah, zrušte zaškrtnutí políčka 'Pouze prioritní' a stiskněte tlačítko 'Obnovit'. \n4. Pokud se chcete nejprve věnovat konkrétním hrám, použijte seznam 'Prioritní' a nastavte si pořadí vybraných her. Nejprve se vyzkouší hry na začátku seznamu a poté hry na konci seznamu. \n5. Ponechte zaškrtnutou možnost 'Pouze prioritní', abyste se vyhnuli vyhledávání her, které nejsou na seznamu priorit. Nebo ne - záleží na vás. \n6. Pomocí seznamu 'vyloučit' můžete aplikaci sdělit, které hry by neměly být vytěženy. \n7. Změna obsahu obou seznamů nebo stavu možnosti Pouze prioritní vyžaduje stisknutí tlačítka Znovu načíst, aby se změna projevila." - } + "help": { + "links": { + "name": "Nápověda", + "inventory": "Zobrazit Twitch Inventář", + "campaigns": "Zobrazit všechny kampaňe a spravovat propojené účty" + }, + "how_it_works": "Jak to funguje", + "how_it_works_text": "Každých ~20 sekund aplikace požádá Twitch o adresu k čistým datám streamu od kanálu, který je v současnosti sledován. Poté stáhne dodatkové informace těchto dat streamu - to stačí k posunu umístění. Všimněte si, že tímto způsobem zcela odpadá nutnost stahovat skutečné streamované video a zvuk. Aby byl stav kanálu (online nebo offline) stále aktuální, je navázáno spojení přes websocket, které přijímá události o spuštění nebo vypnutí streamů nebo aktualizace o aktuálním počtu diváků.", + "getting_started": "Jak začít", + "getting_started_text": "1. Přihlaste se do aplikace. \n2. Ujistěte se, že je váš účet Twitch spojen se všemi reklamními sériemi, které chcete těžit. \n3. Pokud chcete klepnout pouze na veškerý obsah, zrušte zaškrtnutí políčka 'Pouze prioritní' a stiskněte tlačítko 'Obnovit'. \n4. Pokud se chcete nejprve věnovat konkrétním hrám, použijte seznam 'Prioritní' a nastavte si pořadí vybraných her. Nejprve se vyzkouší hry na začátku seznamu a poté hry na konci seznamu. \n5. Ponechte zaškrtnutou možnost 'Pouze prioritní', abyste se vyhnuli vyhledávání her, které nejsou na seznamu priorit. Nebo ne - záleží na vás. \n6. Pomocí seznamu 'vyloučit' můžete aplikaci sdělit, které hry by neměly být vytěženy. \n7. Změna obsahu obou seznamů nebo stavu možnosti Pouze prioritní vyžaduje stisknutí tlačítka Znovu načíst, aby se změna projevila." } + } } diff --git "a/lang/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.json" "b/lang/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.json" index 96350941..4df7b03a 100644 --- "a/lang/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.json" +++ "b/lang/\320\240\321\203\321\201\321\201\320\272\320\270\320\271.json" @@ -1,162 +1,164 @@ -{ - "english_name": "Russian", - "status": { - "terminated": "\nПриложение остановлено.\nЗакройте окно, чтобы выйти из приложения.", - "watching": "Просмотр канала: {channel}", - "goes_online": "Изменение: {channel} онлайн", - "goes_offline": "Изменение: {channel} онлайн", - "claimed_drop": "Drop получено: {drop}", - "claimed_points": "Получены очки канала: {points}", - "earned_points": "За просмотр начисляются очки канала: {points} | Сумма: {balance}", - "no_channel": "Нет участвующих каналов онлайн. Ожидание каналов...", - "no_campaign": "Нет участвующих кампаний онлайн. Ожидание кампаний..." - }, - "login": { - "chrome": { - "startup": "Запуск Браузера...", - "login_to_complete": "Нажмите Log In еще раз, чтобы завершить процесс входа в систему вручную..", - "no_token": "Не найден токен авторизации.", - "closed_window": "Окно Браузера было закрыто до завершения процесса входа в систему." - }, - "error_code": "Код ошибки входа в систему: {error_code}", - "unexpected_content": "Возвращен неожиданный тип содержимого, обычно из-за перенаправления. Требуется ли логин для доступа в Интернет?", - "incorrect_login_pass": "Неправильное имя пользователя или пароль.", - "incorrect_email_code": "Неправильный код электронной почты.", - "incorrect_twofa_code": "Неправильный код 2FA.", - "email_code_required": "Требуется код электронной почты. Пожалуйста, проверьте электронную почту.", - "twofa_code_required": "Требуется код 2FA." - }, - "error": { - "captcha": "Попытка входа в систему была отклонена CAPTCHA.\nПожалуйста, повторите попытку не менее чем через 12 часов.", - "site_down": "Twitch недоступен. Повторите попытку через {seconds} секунд...", - "no_connection": "Невозможно подключиться к Twitch. Повторите попытку через {seconds} секунд..." - }, - "gui": { - "output": "Протокол", - "status": { - "name": "Статус", - "idle": "Вхолостую", - "exiting": "Выход...", - "terminated": "Прекращено", - "cleanup": "Очистка каналов...", - "gathering": "Поиск каналов...", - "switching": "Переключение канала...", - "fetching_inventory": "Получение инвентаря...", - "fetching_campaigns": "Получение кампаний...", - "adding_campaigns": "Добавление кампаний в инвентарь... {counter}" - }, - "tabs": { - "main": "Главная", - "inventory": "Инвентарь", - "settings": "Настройки", - "help": "Помощь" - }, - "tray": { - "notification_title": "Drop получено", - "minimize": "Свернуть в трей", - "show": "Показать", - "quit": "Закрыть" - }, - "login": { - "name": "Авторизация", - "labels": "Статус:\nID пользователя:", - "logged_in": "Авторизован", - "logged_out": "не авторизован", - "logging_in": "Авторизация...", - "required": "Требуется авторизация", - "request": "Пожалуйста, авторизуйтесь, чтобы продолжить.", - "username": "Имя пользователя", - "password": "Пароль", - "twofa_code": "2FA код (опционально)", - "button": "Войти" - }, - "websocket": { - "name": "WebSocket статус", - "websocket": "WebSocket #{id}:", - "initializing": "Инициализация...", - "connected": "Подключено", - "disconnected": "Отключено", - "connecting": "Подключение...", - "disconnecting": "Отключение...", - "reconnecting": "Переподключение..." - }, - "progress": { - "name": "Ход кампании", - "drop": "Drop:", - "game": "Игра:", - "campaign": "Кампания:", - "remaining": "{time} осталось", - "drop_progress": "Прогресс:", - "campaign_progress": "Прогресс:" - }, - "channels": { - "name": "Каналы", - "switch": "Изменить", - "load_points": "Загрузить баллы", - "online": "ОНЛАЙН ✔", - "pending": "ОЖИДАНИЕ ⏳", - "offline": "ОФЛАЙН ❌", - "headings": { - "channel": "Канал", - "status": "Статус", - "game": "Игра", - "viewers": "Зрители", - "points": "Баллы" - } - }, - "inventory": { - "filter": { - "name": "Фильтр", - "show": "Показать:", - "not_linked": "Не связано", - "upcoming": "Будущие", - "expired": "Прошедшие", - "excluded": "Исключенные", - "finished": "Оконченные", - "refresh": "Обновить" - }, - "status": { - "linked": "Связанное ✔", - "not_linked": "Не связанное ❌", - "active": "Активное ✔", - "upcoming": "Будущее ⏳", - "expired": "Прошедшее ❌", - "claimed": "Получено ✔", - "ready_to_claim": "Готово к получению⏳" - }, - "starts": "Начало: {time}", - "ends": "Окончание: {time}", - "allowed_channels": "Участвующие каналы:", - "all_channels": "Все", - "and_more": "и еще {amount}...", - "percent_progress": "{percent} от {minutes} минут", - "minutes_progress": "{minutes} минут" - }, - "settings": { - "general": { - "name": "Общие", - "autostart": "Автозапуск", - "tray": "Автозапуск свёрнутым", - "tray_notifications": "Всплывающие уведомления", - "priority_only": "Только приоритет", - "proxy": "Прокси (Требуется перезапуск):" - }, - "game_name": "Игра", - "priority": "Приоритет", - "exclude": "Исключения", - "reload": "Перезагрузить", - "reload_text": "Большинство изменений требуют перезагрузки, чтобы вступить в силу немедленно: " - }, - "help": { - "links": { - "name": "Полезные ссылки", - "inventory": "Инвентарь Twitch", - "campaigns": "Все кампании Twitch" - }, - "how_it_works": "Как это работает?", - "how_it_works_text": "Каждые ~60 секунд приложение отправляет событие \"минутный просмотр\" на просматриваемый канал. \nЭтого достаточно, чтобы получить Drop. Таким образом, нет необходимости скачивать поток, что экономит трафик. \nДля поддержания актуального состояния каналов в режиме онлайн или офлайн устанавливается соединение websocket, которое проверяет состояние каналов.", - "getting_started": "Первые шаги", - "getting_started_text": "• Войдите в приложение.\n• Убедитесь, что аккаунт Twitch связан со всеми кампаниями, к которым есть интерес.\n• Если вы хотите редактировать все Drops, снимите флажок \"Только приоритет\" и нажмите \"Перезагрузить\".\n• Если необходимо смотреть только определенные игры, используйте список \"Приоритет\", чтобы сузить выбор игр.\n• В списке приоритеты расставлены сверху вниз.\n• Опция \"Только приоритет\" предотвращает просмотр игр, не входящих в список приоритетов.\n• С помощью списка \"Исключения\" можно отфильтровать игры, которые не должны рассматриваться.\n• Если списки или опции были изменены, нажмите \"Перезагрузить\", чтобы изменения были применены." - } - } -} +{ + "english_name": "Russian", + "status": { + "terminated": "\nПриложение остановлено.\nЗакройте окно, чтобы выйти из приложения.", + "watching": "Просмотр канала: {channel}", + "goes_online": "Изменение: {channel} онлайн", + "goes_offline": "Изменение: {channel} онлайн", + "claimed_drop": "Drop получено: {drop}", + "claimed_points": "Получены очки канала: {points}", + "earned_points": "За просмотр начисляются очки канала: {points} | Сумма: {balance}", + "no_channel": "Нет участвующих каналов онлайн. Ожидание каналов...", + "no_campaign": "Нет участвующих кампаний онлайн. Ожидание кампаний..." + }, + "login": { + "unexpected_content": "Возвращен неожиданный тип содержимого, обычно из-за перенаправления. Требуется ли логин для доступа в Интернет?", + "chrome": { + "startup": "Запуск Браузера...", + "login_to_complete": "Нажмите Log In еще раз, чтобы завершить процесс входа в систему вручную..", + "no_token": "Не найден токен авторизации.", + "closed_window": "Окно Браузера было закрыто до завершения процесса входа в систему." + }, + "error_code": "Код ошибки входа в систему: {error_code}", + "incorrect_login_pass": "Неправильное имя пользователя или пароль.", + "incorrect_email_code": "Неправильный код электронной почты.", + "incorrect_twofa_code": "Неправильный код 2FA.", + "email_code_required": "Требуется код электронной почты. Пожалуйста, проверьте электронную почту.", + "twofa_code_required": "Требуется код 2FA." + }, + "error": { + "captcha": "Попытка входа в систему была отклонена CAPTCHA.\nПожалуйста, повторите попытку не менее чем через 12 часов.", + "site_down": "Twitch недоступен. Повторите попытку через {seconds} секунд...", + "no_connection": "Невозможно подключиться к Twitch. Повторите попытку через {seconds} секунд..." + }, + "gui": { + "output": "Протокол", + "status": { + "name": "Статус", + "idle": "Вхолостую", + "exiting": "Выход...", + "terminated": "Прекращено", + "cleanup": "Очистка каналов...", + "gathering": "Поиск каналов...", + "switching": "Переключение канала...", + "fetching_inventory": "Получение инвентаря...", + "fetching_campaigns": "Получение кампаний...", + "adding_campaigns": "Добавление кампаний в инвентарь... {counter}" + }, + "tabs": { + "main": "Главная", + "inventory": "Инвентарь", + "settings": "Настройки", + "help": "Помощь" + }, + "tray": { + "notification_title": "Drop получено", + "minimize": "Свернуть в трей", + "show": "Показать", + "quit": "Закрыть" + }, + "login": { + "name": "Авторизация", + "labels": "Статус:\nID пользователя:", + "logged_in": "Авторизован", + "logged_out": "не авторизован", + "logging_in": "Авторизация...", + "required": "Требуется авторизация", + "request": "Пожалуйста, авторизуйтесь, чтобы продолжить.", + "username": "Имя пользователя", + "password": "Пароль", + "twofa_code": "2FA код (опционально)", + "button": "Войти" + }, + "websocket": { + "name": "WebSocket статус", + "websocket": "WebSocket #{id}:", + "initializing": "Инициализация...", + "connected": "Подключено", + "disconnected": "Отключено", + "connecting": "Подключение...", + "disconnecting": "Отключение...", + "reconnecting": "Переподключение..." + }, + "progress": { + "name": "Ход кампании", + "drop": "Drop:", + "game": "Игра:", + "campaign": "Кампания:", + "remaining": "{time} осталось", + "drop_progress": "Прогресс:", + "campaign_progress": "Прогресс:" + }, + "channels": { + "name": "Каналы", + "switch": "Изменить", + "load_points": "Загрузить баллы", + "online": "ОНЛАЙН ✔", + "pending": "ОЖИДАНИЕ ⏳", + "offline": "ОФЛАЙН ❌", + "headings": { + "channel": "Канал", + "status": "Статус", + "game": "Игра", + "viewers": "Зрители", + "points": "Баллы" + } + }, + "inventory": { + "filter": { + "name": "Фильтр", + "show": "Показать:", + "not_linked": "Не связано", + "upcoming": "Будущие", + "expired": "Прошедшие", + "excluded": "Исключенные", + "finished": "Оконченные", + "refresh": "Обновить" + }, + "status": { + "linked": "Связанное ✔", + "not_linked": "Не связанное ❌", + "active": "Активное ✔", + "upcoming": "Будущее ⏳", + "expired": "Прошедшее ❌", + "claimed": "Получено ✔", + "ready_to_claim": "Готово к получению⏳" + }, + "starts": "Начало: {time}", + "ends": "Окончание: {time}", + "allowed_channels": "Участвующие каналы:", + "all_channels": "Все", + "and_more": "и еще {amount}...", + "percent_progress": "{percent} от {minutes} минут", + "minutes_progress": "{minutes} минут" + }, + "settings": { + "general": { + "name": "Общие", + "dark_theme": "Тёмная тема: ", + "autostart": "Автозапуск", + "tray": "Автозапуск свёрнутым", + "tray_notifications": "Всплывающие уведомления", + "priority_only": "Только приоритет", + "prioritize_by_ending_soonest": "Приоритизация кампаний по дате окончания:", + "proxy": "Прокси (Требуется перезапуск):" + }, + "game_name": "Игра", + "priority": "Приоритет", + "exclude": "Исключения", + "reload": "Перезагрузить", + "reload_text": "Большинство изменений требуют перезагрузки, чтобы вступить в силу немедленно: " + }, + "help": { + "links": { + "name": "Полезные ссылки", + "inventory": "Инвентарь Twitch", + "campaigns": "Все кампании Twitch" + }, + "how_it_works": "Как это работает?", + "how_it_works_text": "Каждые ~20 секунд приложение запрашивает у Twitch URL-адрес необработанных данных потока канала, который просматривается в данный момент. Затем он извлекает метаданные этого потока данных. \nЭтого достаточно, чтобы получить Drop. Таким образом, нет необходимости скачивать поток, что экономит трафик. \nДля поддержания актуального состояния каналов в режиме онлайн или офлайн устанавливается соединение websocket, которое проверяет состояние каналов.", + "getting_started": "Первые шаги", + "getting_started_text": "1. Войдите в приложение.\n2. Убедитесь, что аккаунт Twitch связан со всеми кампаниями, к которым есть интерес.\n3. Если вы хотите редактировать все Drops, снимите флажок \"Только приоритет\" и нажмите \"Перезагрузить\".\n4. Если необходимо смотреть только определенные игры, используйте список \"Приоритет\", чтобы сузить выбор игр.\n5. В списке приоритеты расставлены сверху вниз.\n6. Опция \"Только приоритет\" предотвращает просмотр игр, не входящих в список приоритетов.\n7. С помощью списка \"Исключения\" можно отфильтровать игры, которые не должны рассматриваться.\n8. Если списки или опции были изменены, нажмите \"Перезагрузить\", чтобы изменения были применены." + } + } +} diff --git "a/lang/\320\243\320\272\321\200\320\260\321\227\320\275\321\201\321\214\320\272\320\260.json" "b/lang/\320\243\320\272\321\200\320\260\321\227\320\275\321\201\321\214\320\272\320\260.json" index c9b324c4..51893244 100644 --- "a/lang/\320\243\320\272\321\200\320\260\321\227\320\275\321\201\321\214\320\272\320\260.json" +++ "b/lang/\320\243\320\272\321\200\320\260\321\227\320\275\321\201\321\214\320\272\320\260.json" @@ -1,162 +1,164 @@ { - "english_name": "Ukrainian", + "english_name": "Ukrainian", + "status": { + "terminated": "\nЗастосунок зупинено.\nЗакрийте вікно для виходу з програми.", + "watching": "Переглядає: {channel}", + "goes_online": "{channel} онлайн, зміна...", + "goes_offline": "{channel} офлайн, зміна...", + "claimed_drop": "Отримано дроп: {drop}", + "claimed_points": "Отримано {points} бонусних балів", + "earned_points": "Зароблено {points} балів за перегляд, усього: {balance}", + "no_channel": "Немає активних каналів для перегляду. Очікування...", + "no_campaign": "Немає активних каналів для видобутку дропів. Очікування..." + }, + "login": { + "unexpected_content": "Повернуто неочікуваний тип вмісту, зазвичай через перенаправлення. Чи не потрібно вам увійти задля доступу в інтернет?", + "chrome": { + "startup": "Відкриття браузера...", + "login_to_complete": "Завершіть процедуру входу власноруч, натиснувши кнопку \"Увійти ще раз\".", + "no_token": "Жетон авторизації не знайдено.", + "closed_window": "Вікно браузера було закрито до завершення процедури входу." + }, + "error_code": "Код помилки входу: {error_code}", + "incorrect_login_pass": "Неправильне ім'я користувача або пароль.", + "incorrect_email_code": "Неправильний код електронної пошти.", + "incorrect_twofa_code": "Неправильний код двофакторної аутентифікації.", + "email_code_required": "Потрібен код електронної пошти.", + "twofa_code_required": "Потрібен жетон двофакторної аутентифікації." + }, + "error": { + "captcha": "Ваша спроба входу була відхилена через капчу.\nБудь ласка, спробуйте ще раз через 12 або більше годин.", + "site_down": "Twitch не працює, спроба через {seconds} секунд...", + "no_connection": "Не вдається з'єднатися з Twitch, повторна спроба через {seconds} секунд..." + }, + "gui": { + "output": "Вивід", "status": { - "terminated": "\nЗастосунок зупинено.\nЗакрийте вікно для виходу з програми.", - "watching": "Переглядає: {channel}", - "goes_online": "{channel} онлайн, зміна...", - "goes_offline": "{channel} офлайн, зміна...", - "claimed_drop": "Отримано дроп: {drop}", - "claimed_points": "Отримано {points} бонусних балів", - "earned_points": "Зароблено {points} балів за перегляд, усього: {balance}", - "no_channel": "Немає активних каналів для перегляду. Очікування...", - "no_campaign": "Немає активних каналів для видобутку дропів. Очікування..." + "name": "Стан", + "idle": "Бездіяльність", + "exiting": "Вихід...", + "terminated": "Зупинено", + "cleanup": "Очищення каналів...", + "gathering": "Збір каналів...", + "switching": "Перемикання на канал...", + "fetching_inventory": "Отримання інвентарю...", + "fetching_campaigns": "Отримання кампаній...", + "adding_campaigns": "Додавання кампаній до інвентарю... {counter}" + }, + "tabs": { + "main": "Основне", + "inventory": "Інвентар", + "settings": "Налаштування", + "help": "Інформація" + }, + "tray": { + "notification_title": "Дроп отримано", + "minimize": "Згорнути в лоток", + "show": "Показати", + "quit": "Вийти" }, "login": { - "unexpected_content": "Повернуто неочікуваний тип вмісту, зазвичай через перенаправлення. Чи не потрібно вам увійти задля доступу в інтернет?", - "chrome": { - "startup": "Відкриття браузера...", - "login_to_complete": "Завершіть процедуру входу власноруч, натиснувши кнопку \"Увійти ще раз\".", - "no_token": "Жетон авторизації не знайдено.", - "closed_window": "Вікно браузера було закрито до завершення процедури входу." - }, - "error_code": "Код помилки входу: {error_code}", - "incorrect_login_pass": "Неправильне ім'я користувача або пароль.", - "incorrect_email_code": "Неправильний код електронної пошти.", - "incorrect_twofa_code": "Неправильний код двофакторної аутентифікації.", - "email_code_required": "Потрібен код електронної пошти.", - "twofa_code_required": "Потрібен жетон двофакторної аутентифікації." + "name": "Форма для входу", + "labels": "Стан:\nІдентифікатор користувача:", + "logged_in": "Увійдено", + "logged_out": "Вийдено", + "logging_in": "Вхід...", + "required": "Потрібен вхід", + "request": "Будь ласка, увійдіть, щоб продовжити.", + "username": "Ім'я користувача", + "password": "Пароль", + "twofa_code": "Код двофакторної автентифікації (необов'язково)", + "button": "Вхід" + }, + "websocket": { + "name": "Стан веб-сокета", + "websocket": "Веб-сокет #{id}:", + "initializing": "Ініціалізація...", + "connected": "Підключено", + "disconnected": "Відключено", + "connecting": "З'єднання...", + "disconnecting": "Від'єднання...", + "reconnecting": "Перепідключення..." + }, + "progress": { + "name": "Поступ кампанії", + "drop": "Дроп:", + "game": "Гра:", + "campaign": "Кампанія:", + "remaining": "{time} залишилося", + "drop_progress": "Поступ:", + "campaign_progress": "Поступ:" + }, + "channels": { + "name": "Канали", + "switch": "Перемкнути", + "load_points": "Завантажити бали", + "online": "ОНЛАЙН ✔", + "pending": "ОФЛАЙН ⏳", + "offline": "ОФЛАЙН ❌", + "headings": { + "channel": "Канал", + "status": "Стан", + "game": "Гра", + "viewers": "Глядачі", + "points": "Бали" + } + }, + "inventory": { + "filter": { + "name": "Фільтри", + "show": "Показати лише:", + "not_linked": "Не пов'язано", + "upcoming": "Наближаються", + "expired": "Прострочені", + "excluded": "Виключені", + "finished": "Завершені", + "refresh": "Оновити" + }, + "status": { + "linked": "Пов'язано ✔", + "not_linked": "Не пов'язано ❌", + "active": "Діюча ✔", + "upcoming": "Наближається ⏳", + "expired": "Прострочено ❌", + "claimed": "Отримано ✔", + "ready_to_claim": "Готове до отримання ⏳" + }, + "starts": "Починається {time}", + "ends": "Завершується {time}", + "allowed_channels": "Дозволені канали:", + "all_channels": "Усі", + "and_more": "та ще {amount}...", + "percent_progress": "{percent} від {minutes} хвилин", + "minutes_progress": "{minutes} хвилин" }, - "error": { - "captcha": "Ваша спроба входу була відхилена через капчу.\nБудь ласка, спробуйте ще раз через 12 або більше годин.", - "site_down": "Twitch не працює, спроба через {seconds} секунд...", - "no_connection": "Не вдається з'єднатися з Twitch, повторна спроба через {seconds} секунд..." + "settings": { + "general": { + "name": "Основні", + "dark_theme": "Темна тема:", + "autostart": "Автозапуск: ", + "tray": "Автозапуск у лотку: ", + "tray_notifications": "Сповіщення: ", + "priority_only": "Лише пріоритетні: ", + "prioritize_by_ending_soonest": "Пріоритизувати ті, що закінчуються раніше:", + "proxy": "Проксі (потребує перезапуску):" + }, + "game_name": "Назва гри", + "priority": "Пріоритет", + "exclude": "Виключити", + "reload": "Перезавантажити", + "reload_text": "Більшість змін потребують перезавантаження, щоб набути негайної дії: " }, - "gui": { - "output": "Вивід", - "status": { - "name": "Стан", - "idle": "Бездіяльність", - "exiting": "Вихід...", - "terminated": "Зупинено", - "cleanup": "Очищення каналів...", - "gathering": "Збір каналів...", - "switching": "Перемикання на канал...", - "fetching_inventory": "Отримання інвентарю...", - "fetching_campaigns": "Отримання кампаній...", - "adding_campaigns": "Додавання кампаній до інвентарю... {counter}" - }, - "tabs": { - "main": "Основне", - "inventory": "Інвентар", - "settings": "Налаштування", - "help": "Інформація" - }, - "tray": { - "notification_title": "Дроп отримано", - "minimize": "Згорнути в трей", - "show": "Показати", - "quit": "Вийти" - }, - "login": { - "name": "Форма для входу", - "labels": "Стан:\nІдентифікатор користувача:", - "logged_in": "Увійдено", - "logged_out": "Вийдено", - "logging_in": "Вхід...", - "required": "Потрібен вхід", - "request": "Будь ласка, увійдіть, щоб продовжити.", - "username": "Ім'я користувача", - "password": "Пароль", - "twofa_code": "Код двофакторної автентифікації (необов'язково)", - "button": "Вхід" - }, - "websocket": { - "name": "Стан веб-сокета", - "websocket": "Веб-сокет #{id}:", - "initializing": "Ініціалізація...", - "connected": "Підключено", - "disconnected": "Відключено", - "connecting": "З'єднання...", - "disconnecting": "Від'єднання...", - "reconnecting": "Перепідключення..." - }, - "progress": { - "name": "Поступ кампанії", - "drop": "Дроп:", - "game": "Гра:", - "campaign": "Кампанія:", - "remaining": "{time} залишилося", - "drop_progress": "Поступ:", - "campaign_progress": "Поступ:" - }, - "channels": { - "name": "Канали", - "switch": "Перемкнути", - "load_points": "Завантажити бали", - "online": "ОНЛАЙН \u2714", - "pending": "ОФЛАЙН \u23f3", - "offline": "ОФЛАЙН \u274c", - "headings": { - "channel": "Канал", - "status": "Стан", - "game": "Гра", - "viewers": "Глядачі", - "points": "Бали" - } - }, - "inventory": { - "filter": { - "name": "Фільтри", - "show": "Показати лише:", - "not_linked": "Не пов'язано", - "upcoming": "Наближаються", - "expired": "Прострочені", - "excluded": "Виключені", - "finished": "Завершені", - "refresh": "Оновити" - }, - "status": { - "linked": "Пов'язано \u2714", - "not_linked": "Не пов'язано \u274c", - "active": "Діюча \u2714", - "upcoming": "Наближається \u23f3", - "expired": "Прострочено \u274c", - "claimed": "Отримано \u2714", - "ready_to_claim": "Готове до отримання \u23f3" - }, - "starts": "Починається {time}", - "ends": "Завершується {time}", - "allowed_channels": "Дозволені канали:", - "all_channels": "Усі", - "and_more": "і {amount} більше...", - "percent_progress": "{percent} від {minutes} хвилин", - "minutes_progress": "{minutes} хвилин" - }, - "settings": { - "general": { - "name": "Основні", - "autostart": "Автозапуск: ", - "tray": "Автозапуск у треї: ", - "tray_notifications": "Сповіщення: ", - "priority_only": "Лише пріоритетні: ", - "proxy": "Проксі (потребує перезапуску):" - }, - "game_name": "Назва гри", - "priority": "Пріоритет", - "exclude": "Виключити", - "reload": "Перезавантажити", - "reload_text": "Більшість змін потребують перезавантаження, щоб набути дії: " - }, - "help": { - "links": { - "name": "Корисні посилання", - "inventory": "Переглянути інвентар Twitch", - "campaigns": "Переглянути усі кампанії та керувати пов'язаними обліковими записами" - }, - "how_it_works": "Як це працює?", - "how_it_works_text": "Приблизно кожні 60 секунд програма надсилає подію \"переглянуто хвилину\" на канал, який зараз переглядається - цього достатньо, щоб здобувати дропи. Зауважте, що це повністю обходить необхідність завантажувати будь-які потокові відео та звук. Щоб підтримувати актуальний стан каналів (ОНЛАЙН або ОФЛАЙН), встановлюється з'єднання з веб-сокетом, який отримує події про збільшення або зменшення кількості трансляцій, або оновлення поточної кількості глядачів.", - "getting_started": "Інструкція", - "getting_started_text": "1. Увійдіть в додаток.\n2. Переконайтеся, що ваш обліковий запис Twitch пов'язаний з усіма обліковими записами ігор, з яких ви хочете здобувати дропи.\n3. Якщо ви зацікавлені у здобуванні всього, зніміть прапорець \"Тільки пріоритет\" і натисніть \"Перезавантажити\".\n4. Якщо ви хочете здобувати з певних ігор, скористайтеся списком \"Пріоритет\", щоб створити впорядкований список ігор за вашим вибором. Ігри будуть здобуватися в порядку розташування в списку.\n5. Не знімайте прапорець \"Тільки пріоритет\", щоб уникнути здобування з ігор, які не входять до пріоритетного списку. Або ні - вирішувати вам.\n6. Використовуйте список \"Виключено\", щоб вказати застосунку, з яких ігор ніколи не слід здобувати.\n7. Зміна вмісту будь-якого зі списків або зміна стану опції \"Тільки пріоритет\" вимагає натискання кнопки \"Перезавантажити\" для набуття змінами чинності.\n\nПереклад виконав Дмитро Зозуля" - } + "help": { + "links": { + "name": "Корисні посилання", + "inventory": "Переглянути інвентар Twitch", + "campaigns": "Переглянути усі кампанії та керувати пов'язаними обліковими записами" + }, + "how_it_works": "Як це працює?", + "how_it_works_text": "Приблизно кожні 20 секунд програма запитує у Twitch URL-адресу необробленого потоку даних каналу, який ви зараз переглядаєте. Потім він отримує метадані цього потоку даних - цього достатньо, щоб здобувати дропи. Зауважте, що це повністю обходить необхідність завантажувати будь-які потокові відео та звук. Щоб підтримувати актуальний стан каналів (ОНЛАЙН або ОФЛАЙН), встановлюється з'єднання з веб-сокетом, який отримує події про збільшення або зменшення кількості трансляцій, або оновлення поточної кількості глядачів.", + "getting_started": "Інструкція", + "getting_started_text": "1. Увійдіть у застосунок.\n2. Переконайтеся, що ваш обліковий запис Twitch пов'язаний з усіма обліковими записами ігор, з яких ви хочете здобувати дропи.\n3. Якщо ви зацікавлені у здобуванні всього, зніміть прапорець \"Тільки пріоритет\" і натисніть \"Перезавантажити\".\n4. Якщо ви хочете здобувати дропи з певних ігор, скористайтеся списком \"Пріоритет\", щоб створити впорядкований список ігор за вашим вибором. Ігри будуть здобуватися в порядку розташування в списку.\n5. Не знімайте прапорець \"Тільки пріоритет\", щоб уникнути здобування з ігор, які не входять до пріоритетного списку. Або ні - вирішувати вам.\n6. Використовуйте список \"Виключено\", щоб вказати застосунку, з яких ігор ніколи не слід здобувати.\n7. Зміна вмісту будь-якого зі списків або зміна стану опції \"Тільки пріоритет\" вимагає натискання кнопки \"Перезавантажити\" для набуття змінами чинності.\n\nПереклад виконав @Nollasko" } + } } diff --git "a/lang/\330\247\331\204\330\271\330\261\330\250\331\212\330\251.json" "b/lang/\330\247\331\204\330\271\330\261\330\250\331\212\330\251.json" index fa25730f..1bfe6d2d 100644 --- "a/lang/\330\247\331\204\330\271\330\261\330\250\331\212\330\251.json" +++ "b/lang/\330\247\331\204\330\271\330\261\330\250\331\212\330\251.json" @@ -1,162 +1,164 @@ { - "english_name": "Arabic", + "english_name": "Arabic", + "status": { + "terminated": "تم إنهاء التطبيق. \n أغلق النافذة للخروج من التطبيق.", + "watching": "{channel} :يتم حالياَ مشاهدة", + "goes_online": "...اصبح نشط ، تبديل {channel}", + "goes_offline": "...اصبح غير نشط ، تبديل {channel}", + "claimed_drop": "{drop} :تم الحصول على", + "claimed_points": "تم الحصول على: {points} من النقاط الإضافية", + "earned_points": "تم الحصول على:{points} من نقاط المشاهدة ، الإجمالي: {balance}", + "no_channel": "...لا توجد قنوات نشطة متاحة للمشاهدة. في انتظار قناة نشطة", + "no_campaign": "...لا توجد حملات نشطة من اجل تنقيب الإسقاطات. في انتظار حملة نشطة" + }, + "login": { + "unexpected_content": "تم إرجاع نوع محتوى غير متوقع ، يحدث عادة بسبب إعادة التوجيه. هل تحتاج إلى تسجيل الدخول للوصول إلى الإنترنت؟", + "chrome": { + "startup": "...فتح متصفح كروم", + "login_to_complete": "أكمل إجراء تسجيل الدخول يدويًا عن طريق الضغط على زر تسجيل الدخول مرة أخرى.", + "no_token": ".لا يمكن العثور على رمز التفويض", + "closed_window": ".تم إغلاق نافذة متصفح كروم قبل أن يكتمل إجراء تسجيل الدخول" + }, + "error_code": "{error_code} :رمز خطأ تسجيل الدخول", + "incorrect_login_pass": ".اسم المستخدم أو كلمة المرور غير صحيحة", + "incorrect_email_code": ".كود البريد الإلكتروني غير صحيح", + "incorrect_twofa_code": ".كود المصادقة الثنائية غير صحيح", + "email_code_required": ".كود البريد الإلكتروني مطلوب. تحقق من بريدك الالكتروني", + "twofa_code_required": ".رمز المصادقة الثنائية مطلوب" + }, + "error": { + "captcha": ".يرجى المحاولة مجدداَ بعد مرور 12 ساعة \n .CAPTCHA تم رفض محاولة تسجيل الدخول الخاصة بك من قبل", + "site_down": "...ثانية {seconds} معطل ، إعادة المحاولة خلال Twitch", + "no_connection": "...ثانية {seconds} إعادة المحاولة خلال ، Twitch لا يمكن الإتصال بـ" + }, + "gui": { + "output": "الإخراج", "status": { - "terminated": "تم إنهاء التطبيق. \n أغلق النافذة للخروج من التطبيق.", - "watching": "{channel} :يتم حالياَ مشاهدة", - "goes_online": "...اصبح نشط ، تبديل {channel}", - "goes_offline": "...اصبح غير نشط ، تبديل {channel}", - "claimed_drop": "{drop} :تم الحصول على", - "claimed_points": "تم الحصول على: {points} من النقاط الإضافية", - "earned_points": "تم الحصول على:{points} من نقاط المشاهدة ، الإجمالي: {balance}", - "no_channel": "...لا توجد قنوات نشطة متاحة للمشاهدة. في انتظار قناة نشطة", - "no_campaign": "...لا توجد حملات نشطة من اجل تنقيب الإسقاطات. في انتظار حملة نشطة" + "name": "الحالة", + "idle": "خامل", + "exiting": "...جاري الخروج", + "terminated": "تم الانهاء", + "cleanup": "...مسح القنوات", + "gathering": "...جمع القنوات", + "switching": "...تبديل القناة", + "fetching_inventory": "...جلب محتويات الحقيبة", + "fetching_campaigns": "...جلب الحملات", + "adding_campaigns": "{counter} ...إضافة الحملات إلى الحقيبة" + }, + "tabs": { + "main": "الرئيسية", + "inventory": "الحقيبة", + "settings": "الإعدادات", + "help": "مساعدة" + }, + "tray": { + "notification_title": "تم الحصول على هذا الإسقاط", + "minimize": "تصغير الى الدرج", + "show": "عرض", + "quit": "خروج" }, "login": { - "unexpected_content": "تم إرجاع نوع محتوى غير متوقع ، يحدث عادة بسبب إعادة التوجيه. هل تحتاج إلى تسجيل الدخول للوصول إلى الإنترنت؟", - "chrome": { - "startup": "...فتح متصفح كروم", - "login_to_complete": "أكمل إجراء تسجيل الدخول يدويًا عن طريق الضغط على زر تسجيل الدخول مرة أخرى.", - "no_token": ".لا يمكن العثور على رمز التفويض", - "closed_window": ".تم إغلاق نافذة متصفح كروم قبل أن يكتمل إجراء تسجيل الدخول" - }, - "error_code": "{error_code} :رمز خطأ تسجيل الدخول", - "incorrect_login_pass": ".اسم المستخدم أو كلمة المرور غير صحيحة", - "incorrect_email_code": ".كود البريد الإلكتروني غير صحيح", - "incorrect_twofa_code": ".كود المصادقة الثنائية غير صحيح", - "email_code_required": ".كود البريد الإلكتروني مطلوب. تحقق من بريدك الالكتروني", - "twofa_code_required": ".رمز المصادقة الثنائية مطلوب" + "name": "تسجيل الدخول و معلومات عن الحساب", + "labels": "الحالة ➜\nالمستخدم ID ➜", + "logged_in": "تم تسجيل الدخول", + "logged_out": "تم تسجيل الخروج", + "logging_in": "...تسجيل الدخول", + "required": "تسجيل الدخول مطلوب", + "request": ".الرجاء تسجيل الدخول للمتابعة", + "username": "اسم المستخدم", + "password": "كلمة المرور", + "twofa_code": "المصادقة الثنائية (اختياري)", + "button": "تسجيل الدخول" + }, + "websocket": { + "name": "WebSocket حالة الـ", + "websocket": "WebSocket #{id}:", + "initializing": "...جاري التهيئة", + "connected": "متصل", + "disconnected": "غير متصل", + "connecting": "...جاري الاتصال", + "disconnecting": "...جاري قطع الاتصال", + "reconnecting": "...إعادة الاتصال" + }, + "progress": { + "name": "تقدم الحملة", + "drop": ":الإسقاط", + "game": ":اللعبة", + "campaign": ":الحملة", + "remaining": "{time} متبقي", + "drop_progress": "التقدم ➜", + "campaign_progress": "التقدم ➜" + }, + "channels": { + "name": "القنوات", + "switch": "تبديل", + "load_points": "تحميل النقاط", + "online": "✔ نشط", + "pending": "⏳ غير نشط", + "offline": "❌ غير نشط", + "headings": { + "channel": "القناة", + "status": "الحالة", + "game": "اللعبة", + "viewers": "المشاهدين", + "points": "النقاط" + } + }, + "inventory": { + "filter": { + "name": "تصفية", + "show": "عرض ➜", + "not_linked": "غير مرتبط", + "upcoming": "القادمة", + "expired": "المنتهية", + "excluded": "المستبعدة", + "finished": "المكتملة", + "refresh": "تحديث" + }, + "status": { + "linked": "✔ مرتبط", + "not_linked": "❌ غير مرتبط", + "active": "✔ نشط", + "upcoming": "⏳ قادم", + "expired": "❌ منتهي", + "claimed": "✔ تم الحصول عليه", + "ready_to_claim": "⏳ جاهز للحصول عليه" + }, + "starts": "{time} :يبدأ", + "ends": "{time} :ينتهي", + "allowed_channels": ":القنوات المسموح بها", + "all_channels": "الكل", + "and_more": "...و {amount} قناة اخرى", + "percent_progress": "تم التقدم {percent} من {minutes} دقيقة", + "minutes_progress": "متبقي {minutes} دقيقة" }, - "error": { - "captcha": ".يرجى المحاولة مجدداَ بعد مرور 12 ساعة \n .CAPTCHA تم رفض محاولة تسجيل الدخول الخاصة بك من قبل", - "site_down": "...ثانية {seconds} معطل ، إعادة المحاولة خلال Twitch", - "no_connection": "...ثانية {seconds} إعادة المحاولة خلال ، Twitch لا يمكن الإتصال بـ" + "settings": { + "general": { + "name": "عام", + "dark_theme": "المظهر الداكن: ", + "autostart": "تشغيل تلقائي ", + "tray": "تشغيل تلقائي في الدرج ", + "tray_notifications": "إشعارات الدرج ", + "priority_only": "الأولوية فقط ", + "prioritize_by_ending_soonest": "تحديد الأولويات من خلال الانتهاء في أقرب وقت: ", + "proxy": "بروكسي (يتطلب إعادة التشغيل) " + }, + "game_name": "اسم اللعبة", + "priority": "أولوية", + "exclude": "إستبعاد", + "reload": "إعادة تحميل", + "reload_text": ".ملاحظة: تتطلب معظم التغييرات إعادة التحميل حتى تصبح سارية المفعول " }, - "gui": { - "output": "الإخراج", - "status": { - "name": "الحالة", - "idle": "خامل", - "exiting": "...جاري الخروج", - "terminated": "تم الانهاء", - "cleanup": "...مسح القنوات", - "gathering": "...جمع القنوات", - "switching": "...تبديل القناة", - "fetching_inventory": "...جلب محتويات الحقيبة", - "fetching_campaigns": "...جلب الحملات", - "adding_campaigns": "{counter} ...إضافة الحملات إلى الحقيبة" - }, - "tabs": { - "main": "الرئيسية", - "inventory": "الحقيبة", - "settings": "الإعدادات", - "help": "مساعدة" - }, - "tray": { - "notification_title": "تم الحصول على هذا الإسقاط", - "minimize": "تصغير الى الدرج", - "show": "عرض", - "quit": "خروج" - }, - "login": { - "name": "تسجيل الدخول و معلومات عن الحساب", - "labels": "الحالة \u279C\nالمستخدم ID \u279C", - "logged_in": "تم تسجيل الدخول", - "logged_out": "تم تسجيل الخروج", - "logging_in": "...تسجيل الدخول", - "required": "تسجيل الدخول مطلوب", - "request": ".الرجاء تسجيل الدخول للمتابعة", - "username": "اسم المستخدم", - "password": "كلمة المرور", - "twofa_code": "المصادقة الثنائية (اختياري)", - "button": "تسجيل الدخول" - }, - "websocket": { - "name": "WebSocket حالة الـ", - "websocket": "WebSocket #{id}:", - "initializing": "...جاري التهيئة", - "connected": "متصل", - "disconnected": "غير متصل", - "connecting": "...جاري الاتصال", - "disconnecting": "...جاري قطع الاتصال", - "reconnecting": "...إعادة الاتصال" - }, - "progress": { - "name": "تقدم الحملة", - "drop": ":الإسقاط", - "game": ":اللعبة", - "campaign": ":الحملة", - "remaining": "{time} متبقي", - "drop_progress": "التقدم \u279C", - "campaign_progress": "التقدم \u279C" - }, - "channels": { - "name": "القنوات", - "switch": "تبديل", - "load_points": "تحميل النقاط", - "online": "\u2714 نشط", - "pending": "\u23f3 غير نشط", - "offline": "\u274c غير نشط", - "headings": { - "channel": "القناة", - "status": "الحالة", - "game": "اللعبة", - "viewers": "المشاهدين", - "points": "النقاط" - } - }, - "inventory": { - "filter": { - "name": "تصفية", - "show": "عرض \u279C", - "not_linked": "غير مرتبط", - "upcoming": "القادمة", - "expired": "المنتهية", - "excluded": "المستبعدة", - "finished": "المكتملة", - "refresh": "تحديث" - }, - "status": { - "linked": "\u2714 مرتبط", - "not_linked": "\u274c غير مرتبط", - "active": "\u2714 نشط", - "upcoming": "\u23f3 قادم", - "expired": "\u274c منتهي", - "claimed": "\u2714 تم الحصول عليه", - "ready_to_claim": "\u23f3 جاهز للحصول عليه" - }, - "starts": "{time} :يبدأ", - "ends": "{time} :ينتهي", - "allowed_channels": ":القنوات المسموح بها", - "all_channels": "الكل", - "and_more": "...و {amount} قناة اخرى", - "percent_progress": "تم التقدم {percent} من {minutes} دقيقة", - "minutes_progress": "متبقي {minutes} دقيقة" - }, - "settings": { - "general": { - "name": "عام", - "autostart": "تشغيل تلقائي ", - "tray": "تشغيل تلقائي في الدرج ", - "tray_notifications": "إشعارات الدرج ", - "priority_only": "الأولوية فقط ", - "proxy": "بروكسي (يتطلب إعادة التشغيل) " - }, - "game_name": "اسم اللعبة", - "priority": "أولوية", - "exclude": "إستبعاد", - "reload": "إعادة تحميل", - "reload_text": ".ملاحظة: تتطلب معظم التغييرات إعادة التحميل حتى تصبح سارية المفعول " - }, - "help": { - "links": { - "name": "روابط مفيدة", - "inventory": "Twitch رؤية الحقيبة على", - "campaigns": "الإطلاع على جميع الحملات وإدارة روابط الحساب" - }, - "how_it_works": "!كيف يعمل التطبيق", - "how_it_works_text": " ، كل 60 ثانية تقريباَ يرسل التطبيق حدثاَ \"دقيقة تمت مشاهدتها\" إلى القناة التي تتم مشاهدتها حالياَ\n.وهذا يكفي لتعزيز تقدم الإسقاطات\n.لاحظ أن هذا يتخطى تمامًا الحاجة إلى تنزيل أي فيديو أو صوت فعلي\nو للمحافظة على تحديث حالة القنوات هناك اتصال ويب سوكت والذي يتلقى احداثاَ\nحول البثوت المباشرة التي تصبح نشطة او غير نشطة ، او عن العدد الحالي للمشاهدين", - "getting_started": "البدء", - "getting_started_text": "1. قم بتسجيل الدخول للتطبيق\n2. مرتبط بجميع الحملات المهتم بتنقيبها Twitch تأكد من ان حسابك على\n3. إذا كنت مهتم بتنقيب كل شي فقم بإلغاء تحديد خيار \"الأولوية فقط\" واضغط على إعادة التحميل\n4. اذا كنت تريد تنقيب لعبة معينة اولا ، فقم بإستخدام قائمة \"أولوية\" لإعداد قائمة مرتبة من الألعاب الي تختارها\n وسيتم محاولة تعدين الألعاب من اعلى القائمة اولاَ ، قبل الألعاب الموجودة في الاسفل\n5. \"قم بتحديد خيار \"الأولوية فقط\" ، لتجنب تنقيب العاب غير مدرجة في قائمة \"أولوية\n6. استخدم قائمة \"إستبعاد\" لإخبار التطبيق بالألعاب التي يجب ألا يتم تنقيبها ابداَ\n7. \"لإحداث تغيير في احد القوائم او تحديد او الغاء تحديد خيار \"الأولويةفقط\nيتطلب الضغط على خيار \"إعادة التحميل\" لتصبح التغييرات سارية المفعول" - } + "help": { + "links": { + "name": "روابط مفيدة", + "inventory": "Twitch رؤية الحقيبة على", + "campaigns": "الإطلاع على جميع الحملات وإدارة روابط الحساب" + }, + "how_it_works": "!كيف يعمل التطبيق", + "how_it_works_text": " ، كل 60 ثانية تقريباَ يرسل التطبيق حدثاَ \"دقيقة تمت مشاهدتها\" إلى القناة التي تتم مشاهدتها حالياَ\n.وهذا يكفي لتعزيز تقدم الإسقاطات\n.لاحظ أن هذا يتخطى تمامًا الحاجة إلى تنزيل أي فيديو أو صوت فعلي\nو للمحافظة على تحديث حالة القنوات هناك اتصال ويب سوكت والذي يتلقى احداثاَ\nحول البثوت المباشرة التي تصبح نشطة او غير نشطة ، او عن العدد الحالي للمشاهدين", + "getting_started": "البدء", + "getting_started_text": "1. قم بتسجيل الدخول للتطبيق\n2. مرتبط بجميع الحملات المهتم بتنقيبها Twitch تأكد من ان حسابك على\n3. إذا كنت مهتم بتنقيب كل شي فقم بإلغاء تحديد خيار \"الأولوية فقط\" واضغط على إعادة التحميل\n4. اذا كنت تريد تنقيب لعبة معينة اولا ، فقم بإستخدام قائمة \"أولوية\" لإعداد قائمة مرتبة من الألعاب الي تختارها\n وسيتم محاولة تعدين الألعاب من اعلى القائمة اولاَ ، قبل الألعاب الموجودة في الاسفل\n5. \"قم بتحديد خيار \"الأولوية فقط\" ، لتجنب تنقيب العاب غير مدرجة في قائمة \"أولوية\n6. استخدم قائمة \"إستبعاد\" لإخبار التطبيق بالألعاب التي يجب ألا يتم تنقيبها ابداَ\n7. \"لإحداث تغيير في احد القوائم او تحديد او الغاء تحديد خيار \"الأولويةفقط\nيتطلب الضغط على خيار \"إعادة التحميل\" لتصبح التغييرات سارية المفعول" } + } } diff --git "a/lang/\347\256\200\344\275\223\344\270\255\346\226\207.json" "b/lang/\347\256\200\344\275\223\344\270\255\346\226\207.json" index f98d36a2..edd6edca 100644 --- "a/lang/\347\256\200\344\275\223\344\270\255\346\226\207.json" +++ "b/lang/\347\256\200\344\275\223\344\270\255\346\226\207.json" @@ -1,162 +1,164 @@ { - "english_name": "Simplified Chinese", + "english_name": "Simplified Chinese", + "status": { + "terminated": "\n应用程序已终止,请关闭窗口以退出应用程序。", + "watching": "正在观看: {channel}", + "goes_online": "{channel} 该频道已上线, 正在切换...", + "goes_offline": "{channel} 该频道已离线, 正在切换...", + "claimed_drop": "领取的掉宝: {drop}", + "claimed_points": "领取的积分奖励: {points}", + "earned_points": "观看直播获得积分: {points}, 总积分: {balance}", + "no_channel": "没有可观看的频道,等待一个在线直播频道...", + "no_campaign": "没有可用于掉宝的活动,等待一个有效的掉宝活动..." + }, + "login": { + "unexpected_content": "返回的内容类型有误通常是由于被重定向.您需要设置VPN或者确认登录页面才能联网吗?", + "chrome": { + "startup": "正在打开Chrome浏览器...", + "login_to_complete": "请再次点击登录按钮来完成登陆.", + "no_token": "无法获取授权令牌.", + "closed_window": "在登录完成之前关闭了Chrome浏览器." + }, + "error_code": "登录出错: {error_code}", + "incorrect_login_pass": "用户名或密码错误.", + "incorrect_email_code": "电子邮箱验证码错误.", + "incorrect_twofa_code": "双重验证2FA令牌错误.", + "email_code_required": "需要电子邮件验证码 查看你的邮件.", + "twofa_code_required": "需要双重验证2FA令牌." + }, + "error": { + "captcha": "您的登录存在异常,Twitch官方已进行限制,请在12小时后重试.", + "site_down": "Twitch无法连接,{seconds} 秒后重试...", + "no_connection": "无法连接到Twitch,请确保已经开启VPN并添加了代理,{seconds} 秒后重试..." + }, + "gui": { + "output": "输出日志", "status": { - "terminated": "\n应用程序已终止,请关闭窗口以退出应用程序。", - "watching": "正在观看: {channel}", - "goes_online": "{channel} 该频道已上线, 正在切换...", - "goes_offline": "{channel} 该频道已离线, 正在切换...", - "claimed_drop": "领取的掉宝: {drop}", - "claimed_points": "领取的积分奖励: {points}", - "earned_points": "观看直播获得积分: {points}, 总积分: {balance}", - "no_channel": "没有可观看的频道,等待一个在线直播频道...", - "no_campaign": "没有可用于掉宝的活动,等待一个有效的掉宝活动..." + "name": "状态", + "idle": "已完成获取", + "exiting": "正在退出...", + "terminated": "应用已终止运行", + "cleanup": "清除频道中...", + "gathering": "搜索直播频道...", + "switching": "切换直播频道中...", + "fetching_inventory": "获取库存中...", + "fetching_campaigns": "获取掉宝活动...", + "adding_campaigns": "将掉宝活动列表添加至库存... {counter}" + }, + "tabs": { + "main": "主面板", + "inventory": "掉宝库存", + "settings": "设置", + "help": "帮助" + }, + "tray": { + "notification_title": "开始掉宝活动", + "minimize": "窗口最小化", + "show": "掉宝活动", + "quit": "退出" }, "login": { - "chrome": { - "startup": "正在打开Chrome浏览器...", - "login_to_complete": "请再次点击登录按钮来完成登陆.", - "no_token": "无法获取授权令牌.", - "closed_window": "在登录完成之前关闭了Chrome浏览器." - }, - "error_code": "登录出错: {error_code}", - "unexpected_content": "返回的内容类型有误通常是由于被重定向.您需要设置VPN或者确认登录页面才能联网吗?", - "incorrect_login_pass": "用户名或密码错误.", - "incorrect_email_code": "电子邮箱验证码错误.", - "incorrect_twofa_code": "双重验证2FA令牌错误.", - "email_code_required": "需要电子邮件验证码 查看你的邮件.", - "twofa_code_required": "需要双重验证2FA令牌." + "name": "登录Twitch账号", + "labels": "状态:\n用户ID:", + "logged_in": "已登录", + "logged_out": "未登录", + "logging_in": "正在登录中...", + "required": "请先登录", + "request": "请先登录以访问更多内容.", + "username": "用户名", + "password": "密码", + "twofa_code": "邮箱2FA令牌", + "button": "登录" + }, + "websocket": { + "name": "网络协议连接状态", + "websocket": "Websocket #{id}:", + "initializing": "初始化...", + "connected": "已连接", + "disconnected": "断开连接", + "connecting": "连接中...", + "disconnecting": "断开连接中...", + "reconnecting": "重新连接中..." + }, + "progress": { + "name": "掉宝活动进度", + "drop": "掉宝奖励:", + "game": "游戏:", + "campaign": "掉宝活动名称:", + "remaining": "剩余 {time}", + "drop_progress": "掉宝进度:", + "campaign_progress": "活动进度:" + }, + "channels": { + "name": "活动频道", + "switch": "切换", + "load_points": "加载积分", + "online": "ONLINE ✔", + "pending": "OFFLINE ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "直播频道", + "status": "在线状态", + "game": "游戏", + "viewers": "观众", + "points": "积分" + } + }, + "inventory": { + "filter": { + "name": "筛选", + "show": "掉宝活动:", + "not_linked": "未关联账户的游戏掉宝", + "upcoming": "即将上线", + "expired": "已结束", + "excluded": "未添加的掉宝活动", + "finished": "已完成", + "refresh": "刷新" + }, + "status": { + "linked": "已关联 ✔", + "not_linked": "未关联账户 ❌", + "active": "已上线 ✔", + "upcoming": "即将上线 ⏳", + "expired": "已结束 ❌", + "claimed": "已领取 ✔", + "ready_to_claim": "可以领取 ⏳" + }, + "starts": "开始时间: {time}", + "ends": "结束时间: {time}", + "allowed_channels": "允许的频道:", + "all_channels": "全部", + "and_more": "还有 {amount} 个...", + "percent_progress": "{minutes} 分钟的 {percent}", + "minutes_progress": "{minutes} 分钟" }, - "error": { - "captcha": "您的登录存在异常,Twitch官方已进行限制,请在12小时后重试.", - "site_down": "Twitch无法连接,{seconds} 秒后重试...", - "no_connection": "无法连接到Twitch,请确保已经开启VPN并添加了代理,{seconds} 秒后重试..." + "settings": { + "general": { + "name": "功能设置", + "dark_theme": "黑夜模式: ", + "autostart": "开机自启动: ", + "tray": "开机自启动并最小化: ", + "tray_notifications": "启用托盘通知: ", + "priority_only": "仅参与优先掉宝游戏: ", + "prioritize_by_ending_soonest": "按掉宝游戏的结束日期决定优先度: ", + "proxy": "代理:" + }, + "game_name": "游戏名称", + "priority": "优先掉宝游戏", + "exclude": "不参与掉宝游戏", + "reload": "刷新", + "reload_text": "大多数设置更改后需要重新启动软件或刷新才能生效: " }, - "gui": { - "output": "输出日志", - "status": { - "name": "状态", - "idle": "已完成获取", - "exiting": "正在退出...", - "terminated": "应用已终止运行", - "cleanup": "清除频道中...", - "gathering": "搜索直播频道...", - "switching": "切换直播频道中...", - "fetching_inventory": "获取库存中...", - "fetching_campaigns": "获取掉宝活动...", - "adding_campaigns": "将掉宝活动列表添加至库存... {counter}" - }, - "tabs": { - "main": "主面板", - "inventory": "掉宝库存", - "settings": "设置", - "help": "帮助" - }, - "tray": { - "notification_title": "开始掉宝活动", - "minimize": "窗口最小化", - "show": "掉宝活动", - "quit": "退出" - }, - "login": { - "name": "登录Twitch账号", - "labels": "状态:\n用户ID:", - "logged_in": "已登录", - "logged_out": "未登录", - "logging_in": "正在登录中...", - "required": "请先登录", - "request": "请先登录以访问更多内容.", - "username": "用户名", - "password": "密码", - "twofa_code": "邮箱2FA令牌", - "button": "登录" - }, - "websocket": { - "name": "网络协议连接状态", - "websocket": "Websocket #{id}:", - "initializing": "初始化...", - "connected": "已连接", - "disconnected": "断开连接", - "connecting": "连接中...", - "disconnecting": "断开连接中...", - "reconnecting": "重新连接中..." - }, - "progress": { - "name": "掉宝活动进度", - "drop": "掉宝奖励:", - "game": "游戏:", - "remaining": "剩余 {time}", - "campaign": "掉宝活动名称:", - "drop_progress": "掉宝进度:", - "campaign_progress": "活动进度:" - }, - "channels": { - "name": "活动频道", - "switch": "切换", - "load_points": "加载积分", - "online": "ONLINE \u2714", - "pending": "OFFLINE \u23f3", - "offline": "OFFLINE \u274c", - "headings": { - "channel": "直播频道", - "game": "游戏", - "points": "积分", - "status": "在线状态", - "viewers": "观众" - } - }, - "inventory": { - "filter": { - "name": "筛选", - "show": "掉宝活动:", - "not_linked": "未关联账户的游戏掉宝", - "expired": "已结束", - "excluded": "未添加的掉宝活动", - "upcoming": "即将上线", - "finished": "已完成", - "refresh": "刷新" - }, - "status": { - "linked": "已关联 \u2714", - "not_linked": "未关联账户 \u274c", - "active": "已上线 \u2714", - "upcoming": "即将上线 \u23f3", - "expired": "已结束 \u274c", - "claimed": "已领取 \u2714", - "ready_to_claim": "可以领取 \u23f3" - }, - "starts": "开始时间: {time}", - "ends": "结束时间: {time}", - "allowed_channels": "允许的频道:", - "all_channels": "全部", - "and_more": "还有 {amount} 个...", - "percent_progress": "{minutes} 分钟的 {percent}", - "minutes_progress": "{minutes} 分钟" - }, - "settings": { - "general": { - "name": "功能设置", - "autostart": "开机自启动: ", - "tray": "开机自启动并最小化: ", - "tray_notifications": "启用托盘通知: ", - "priority_only": "仅参与优先掉宝游戏: ", - "proxy": "代理:" - }, - "game_name": "游戏名称", - "priority": "优先掉宝游戏", - "exclude": "不参与掉宝游戏", - "reload": "刷新", - "reload_text": "大多数设置更改后需要重新启动软件或刷新才能生效: " - }, - "help": { - "links": { - "name": "帮助", - "inventory": "查看Twitch库存", - "campaigns": "查看所有掉宝活动并管理连接账号" - }, - "how_it_works": "工作原理", - "how_it_works_text": "每隔约 60 秒,应用程序会向当前正在观看的频道发送一个“观看了一分钟”事件 - 这足以推进掉宝进度。这完全不需要下载任何实际视频流和声音。为了使频道的状态(在线或离线)保持最新,建立了websocket连接,用于接收有关直播开播下播事件,或当前观众数量的更新。", - "getting_started": "入门设置", - "getting_started_text": "1. 登录应用程序。\n2.确保所有感兴趣挖掘的游戏的账号已连接到您的Twitch账号。\n3.如果您想挖掘所有掉宝,请不要勾选“仅参与优先掉宝游戏”,然后按“刷新”。\n4.如果您想优先挖掘特定游戏,请使用“优先掉宝游戏”列表设置您想挖掘的游戏的优先顺序。程序将尝试先挖掘列表顶部的游戏,然后再挖掘后边的游戏。\n5.勾选“仅参与优先掉宝游戏”时,不会挖掘不在优先列表中的游戏。勾不勾选取决于你。\n6。使用“不参与掉宝游戏”列表设置永不挖掘的游戏。\n7.更改任一列表的内容,或更改“仅参与优先掉宝游戏”勾选状态,需要手动按“刷新”才能使更改生效。" - } + "help": { + "links": { + "name": "帮助", + "inventory": "查看Twitch库存", + "campaigns": "查看所有掉宝活动并管理连接账号" + }, + "how_it_works": "工作原理", + "how_it_works_text": "每隔约 20 秒,程序就会向 Twitch 询问当前正在观看的频道的原始数据流 URL。然后,它会获取这个数据流的元数据。 - 这足以推进掉宝进度。这完全不需要下载任何实际的视频流和音频流。为了使频道的状态(在线或离线)保持最新,程序会建立 Websocket 连接,用于接收有关频道开播和下播的事件,并更新当前的观众数量。", + "getting_started": "入门设置", + "getting_started_text": "1. 登录应用程序。\n2.确保所有感兴趣挖掘的游戏的账号已连接到您的Twitch账号。\n3.如果您想挖掘所有掉宝,请不要勾选“仅参与优先掉宝游戏”,然后按“刷新”。\n4.如果您想优先挖掘特定游戏,请使用“优先掉宝游戏”列表设置您想挖掘的游戏的优先顺序。程序将尝试先挖掘列表顶部的游戏,然后再挖掘后边的游戏。\n5.勾选“仅参与优先掉宝游戏”时,不会挖掘不在优先列表中的游戏。勾不勾选取决于你。\n6。使用“不参与掉宝游戏”列表设置永不挖掘的游戏。\n7.更改任一列表的内容,或更改“仅参与优先掉宝游戏”勾选状态,需要手动按“刷新”才能使更改生效。" } + } } diff --git "a/lang/\347\271\201\351\253\224\344\270\255\346\226\207.json" "b/lang/\347\271\201\351\253\224\344\270\255\346\226\207.json" index fd3bcf3a..aeb97384 100644 --- "a/lang/\347\271\201\351\253\224\344\270\255\346\226\207.json" +++ "b/lang/\347\271\201\351\253\224\344\270\255\346\226\207.json" @@ -1,161 +1,164 @@ { - "english_name": "Traditional Chinese", + "english_name": "Traditional Chinese", + "status": { + "terminated": "\n應用程序已終止,請關閉窗口以退出應用程序。", + "watching": "正在觀看: {channel}", + "goes_online": "{channel} 該頻道已上線, 正在切換...", + "goes_offline": "{channel} 該頻道已離線, 正在切換...", + "claimed_drop": "領取的掉寶: {drop}", + "claimed_points": "領取的積分獎勵: {points}", + "earned_points": "觀看直播獲得積分: {points}, 總積分: {balance}", + "no_channel": "沒有可觀看的頻道,等待一個在線直播頻道...", + "no_campaign": "沒有可用於掉寶的活動,等待一個有效的掉寶活動..." + }, + "login": { + "unexpected_content": "返回的內容類型有誤通常是由於被重定向.您需要設置VPN或者確認登錄頁面才能聯網嗎?", + "chrome": { + "startup": "正在打開Chrome瀏覽器...", + "login_to_complete": "請再次點擊登錄按鈕來完成登陸.", + "no_token": "無法獲取授權令牌.", + "closed_window": "在登錄完成之前關閉了Chrome瀏覽器." + }, + "error_code": "登錄出錯: {error_code}", + "incorrect_login_pass": "用戶名或密碼錯誤.", + "incorrect_email_code": "電子郵箱驗證碼錯誤.", + "incorrect_twofa_code": "雙重驗證2FA令牌錯誤.", + "email_code_required": "需要電子郵件驗證碼 查看你的郵件.", + "twofa_code_required": "需要雙重驗證2FA令牌." + }, + "error": { + "captcha": "您的登錄存在異常,Twitch官方已進行限制,請在12小時後重試.", + "site_down": "Twitch無法連接,{seconds} 秒後重試...", + "no_connection": "無法連接到Twitch,請確保已經開啟VPN並添加了代理,{seconds} 秒後重試..." + }, + "gui": { + "output": "輸出日志", "status": { - "terminated": "\n應用程式已結束運行,請關閉窗口已退出應用程式。", - "watching": "正在觀看: {channel}", - "goes_online": "{channel} 該頻道已開始實況, 正在跳轉...", - "goes_offline": "{channel} 該頻道已結束實況, 正在跳轉...", - "claimed_drop": "領取的掉寶: {drop}", - "claimed_points": "領取的積分獎勵: {points}", - "earned_points": "觀看實況獲得積分: {points}, 總積分: {balance}", - "no_channel": "沒有可觀看的實況,等待一個可領取掉寶的實況開始實況...", - "no_campaign": "沒有可用於掉寶的活動,等待一個有效的掉寶活動..." + "name": "狀態", + "idle": "已完成獲取", + "exiting": "正在退出...", + "terminated": "應用已終止運行", + "cleanup": "清除頻道中...", + "gathering": "搜索直播頻道...", + "switching": "切換直播頻道中...", + "fetching_inventory": "獲取庫存中...", + "fetching_campaigns": "獲取掉寶活動...", + "adding_campaigns": "將掉寶活動列表添加至庫存... {counter}" + }, + "tabs": { + "main": "主面板", + "inventory": "掉寶庫存", + "settings": "設置", + "help": "幫助" + }, + "tray": { + "notification_title": "開始掉寶活動", + "minimize": "窗口最小化", + "show": "掉寶活動", + "quit": "退出" }, "login": { - "chrome": { - "startup": "正在開啟Chrome瀏覽器...", - "login_to_complete": "請再次點擊登錄已完成登錄.", - "no_token": "無法獲取授權令牌.", - "closed_window": "在登錄完成之前,Chrome瀏覽器已被關閉." - }, - "error_code": "登錄出現錯誤: {error_code}", - "unexpected_content": "返回的內容類型有誤,通常是由於被重新定向,您需要設置VPN或者確認登錄頁面才能連上網路嗎?", - "incorrect_login_pass": "帳號或密碼錯誤.", - "incorrect_email_code": "電子郵件驗證碼錯誤.", - "incorrect_twofa_code": "雙重驗證2FA令牌錯誤.", - "email_code_required": "需要電子信箱驗證碼,請查看你的信箱.", - "twofa_code_required": "需要雙重驗證2FA令牌." + "name": "登錄Twitch賬號", + "labels": "狀態:\n用戶ID:", + "logged_in": "已登錄", + "logged_out": "未登錄", + "logging_in": "正在登錄中...", + "required": "請先登錄", + "request": "請先登錄以訪問更多內容.", + "username": "用戶名", + "password": "密碼", + "twofa_code": "郵箱2FA令牌", + "button": "登錄" + }, + "websocket": { + "name": "網絡協議連接狀態", + "websocket": "Websocket #{id}:", + "initializing": "初始化...", + "connected": "已連接", + "disconnected": "斷開連接", + "connecting": "連接中...", + "disconnecting": "斷開連接中...", + "reconnecting": "重新連接中..." + }, + "progress": { + "name": "掉寶活動進度", + "drop": "掉寶獎勵:", + "game": "遊戲:", + "campaign": "掉寶活動名稱:", + "remaining": "剩余 {time}", + "drop_progress": "掉寶進度:", + "campaign_progress": "活動進度:" + }, + "channels": { + "name": "活動頻道", + "switch": "切換", + "load_points": "加載積分", + "online": "ONLINE ✔", + "pending": "OFFLINE ⏳", + "offline": "OFFLINE ❌", + "headings": { + "channel": "直播頻道", + "status": "在線狀態", + "game": "遊戲", + "viewers": "觀眾", + "points": "積分" + } + }, + "inventory": { + "filter": { + "name": "篩選", + "show": "掉寶活動:", + "not_linked": "未關聯賬戶的遊戲掉寶", + "upcoming": "即將上線", + "expired": "已結束", + "excluded": "未添加的掉寶活動", + "finished": "已完成", + "refresh": "刷新" + }, + "status": { + "linked": "已關聯 ✔", + "not_linked": "未關聯賬戶 ❌", + "active": "已上線 ✔", + "upcoming": "即將上線 ⏳", + "expired": "已結束 ❌", + "claimed": "已領取 ✔", + "ready_to_claim": "可以領取 ⏳" + }, + "starts": "開始時間: {time}", + "ends": "結束時間: {time}", + "allowed_channels": "允許的頻道:", + "all_channels": "全部", + "and_more": "還有 {amount} 個...", + "percent_progress": "{minutes} 分鐘的 {percent}", + "minutes_progress": "{minutes} 分鐘" }, - "error": { - "captcha": "您的登錄存在異常,Twitch官方已進行限制,請在12小時後重試.", - "site_down": "Twitch無法連接,{seconds} 秒後重試...", - "no_connection": "無法連接到Twitch,請確認已經開啟VPN並添加了代理,{seconds} 秒後重試..." + "settings": { + "general": { + "name": "功能設置", + "dark_theme": "暗色主題: ", + "autostart": "開機自啟動: ", + "tray": "開機自啟動並最小化: ", + "tray_notifications": "啟用托盤通知: ", + "priority_only": "僅參與優先掉寶遊戲: ", + "prioritize_by_ending_soonest": "按掉寶遊戲的結束日期決定優先度: ", + "proxy": "代理:" + }, + "game_name": "遊戲名稱", + "priority": "優先掉寶遊戲", + "exclude": "不參與掉寶遊戲", + "reload": "刷新", + "reload_text": "大多數設置更改後需要重新啟動軟件或刷新才能生效:" }, - "gui": { - "output": "輸出日誌", - "status": { - "name": "狀態", - "idle": "已完成獲取", - "exiting": "正在退出...", - "terminated": "應用程式已終止", - "cleanup": "清除頻道中...", - "gathering": "搜索實況頻道...", - "switching": "切換實況頻道...", - "fetching_inventory": "獲取庫存中...", - "fetching_campaigns": "獲取掉寶活動...", - "adding_campaigns": "將掉寶活動列表添加至庫存... {counter}" - }, - "tabs": { - "main": "主面板", - "inventory": "掉寶庫存", - "settings": "設置", - "help": "幫助" - }, - "tray": { - "notification_title": "開始掉寶活動", - "minimize": "視窗最小化,縮至右下角", - "show": "掉寶活動", - "quit": "退出" - }, - "login": { - "name": "登錄Twtich帳號", - "labels": "狀態:\n用戶ID:", - "logged_in": "已登錄", - "logged_out": "未登錄", - "logging_in": "正在登錄中...", - "required": "請先登錄", - "request": "請先登錄以訪問更多內容.", - "username": "帳號", - "password": "密碼", - "twofa_code": "信箱2FA令牌", - "button": "登錄" - }, - "websocket": { - "name": "網路協議連接狀態", - "websocket": "Websocket #{id}:", - "initializing": "初始化...", - "connected": "已連接", - "disconnected": "斷開連接", - "connecting": "連接中...", - "disconnecting": "斷開連接...", - "reconnecting": "重新連接中..." - }, - "progress": { - "name": "掉寶活動進度", - "drop": "掉寶獎勵:", - "game": "遊戲:", - "remaining": "剩餘 {time}", - "campaign": "掉寶活動名稱:", - "drop_progress": "掉寶進度:", - "campaign_progress": "活動進度:" - }, - "channels": { - "name": "活動頻道", - "switch": "切換", - "load_points": "讀取積分", - "online": "ONLINE \u2714", - "pending": "OFFLINE \u23f3", - "offline": "OFFLINE \u274c", - "headings": { - "channel": "實況頻道", - "game": "遊戲", - "points": "積分", - "status": "在現狀態", - "viewers": "觀眾" - } - }, - "inventory": { - "filter": { - "name": "篩選", - "show": "掉寶活動:", - "not_linked": "未連結", - "expired": "已結束", - "excluded": "未添加的掉寶活動", - "upcoming": "即將開啟", - "finished": "已完成", - "refresh": "刷新" - }, - "status": { - "linked": "已連結 \u2714", - "not_linked": "未連結帳戶 \u274c", - "active": "已上線 \u2714", - "upcoming": "即將開啟 \u23f3", - "expired": "已結束 \u274c", - "claimed": "已領取 \u2714", - "ready_to_claim": "可以領取 \u23f3" - }, - "starts": "開始時間: {time}", - "ends": "結束時間: {time}", - "allowed_channels": "允許的頻道:", - "all_channels": "全部", - "and_more": "還有 {amount} 個...", - "percent_progress": "{minutes} 分鐘的 {percent}", - "minutes_progress": "{minutes} 分鐘" - }, - "settings": { - "general": { - "name": "功能設定", - "autostart": "開機自動啟動: ", - "tray": "開機自動啟動並最小化: ", - "priority_only": "僅參與優先掉寶遊戲: ", - "proxy": "代理:" - }, - "game_name": "遊戲名稱", - "priority": "優先掉寶遊戲", - "exclude": "不參與掉寶遊戲", - "reload": "刷新", - "reload_text": "大多數設定更改後,需要重新啟動軟件或刷新才能生效: " - }, - "help": { - "links": { - "name": "幫助", - "inventory": "查看Twitch庫存", - "campaigns": "查看所有掉寶活動並管理連結帳號" - }, - "how_it_works": "工作原理", - "how_it_works_text": "每隔約60秒,應用程式會向當前正在觀看的實況頻道發送一個“觀看了一分鐘”的事件 - 這足以推進掉寶進度。這完全不需要下載任何實際影片串流和聲音。為了使頻道的狀態(在線或離線)保持最新狀態,建立了websocket連接,用於接受有關實況開始及結束事件,或當前觀眾數量的更新。", - "getting_started": "開始設定", - "getting_started_text": "1.登錄應用程式。\n2.確保所有感興趣挖掘的遊戲的帳號已連結到您的Twitch帳號。\n3.如果您想挖掘所有掉寶,請不要勾選“僅參與優先掉寶遊戲”,然後按“刷新”。\n4.如果您想優先挖掘特定遊戲,請使用“優先掉寶遊戲”列表設置您想挖掘的遊戲的優先順序。應用程式將嘗試先挖掘列表頂部的遊戲,然後再挖掘後面的遊戲。\n5.勾選“僅參與優先掉寶遊戲”時不會挖掘不在優先列表中的遊戲。勾不勾選取決於你。\n6.使用“不參與掉寶遊戲”列表設置永不挖掘的遊戲。\n7.更改任一列表的內容,或更改“僅參與優先掉寶遊戲”勾選狀態,需要手動按“刷新”才能使更改生效。" - } + "help": { + "links": { + "name": "幫助", + "inventory": "查看Twitch庫存", + "campaigns": "查看所有掉寶活動並管理連接賬號" + }, + "how_it_works": "工作原理", + "how_it_works_text": "每隔約 20 秒,程序就會向 Twitch 詢問當前正在觀看的頻道的原始數據流 URL。然後,它會獲取這個數據流的元數據。 - 這足以推進掉寶進度。這完全不需要下載任何實際的視頻流和音頻流。為了使頻道的狀態(在線或離線)保持最新,程序會建立 Websocket 連接,用於接收有關頻道開播和下播的事件,並更新當前的觀眾數量。", + "getting_started": "入門設置", + "getting_started_text": "1. 登錄應用程序。\n2.確保所有感興趣挖掘的遊戲的賬號已連接到您的Twitch賬號。\n3.如果您想挖掘所有掉寶,請不要勾選“僅參與優先掉寶遊戲”,然後按“刷新”。\n4.如果您想優先挖掘特定遊戲,請使用“優先掉寶遊戲”列表設置您想挖掘的遊戲的優先順序。程序將嘗試先挖掘列表頂部的遊戲,然後再挖掘後邊的遊戲。\n5.勾選“僅參與優先掉寶遊戲”時,不會挖掘不在優先列表中的遊戲。勾不勾選取決於你。\n6。使用“不參與掉寶遊戲”列表設置永不挖掘的遊戲。\n7.更改任一列表的內容,或更改“僅參與優先掉寶遊戲”勾選狀態,需要手動按“刷新”才能使更改生效。" } + } } diff --git a/main.py b/main.py index f87c60d9..5b51ab27 100644 --- a/main.py +++ b/main.py @@ -2,9 +2,11 @@ # import an additional thing for proper PyInstaller freeze support from multiprocessing import freeze_support +from datetime import datetime if __name__ == "__main__": + print(f"{datetime.now().strftime('%Y-%m-%d %X')}: Starting: Twitch Drops Miner") freeze_support() import io import sys @@ -103,12 +105,12 @@ def debug_gql(self) -> int: parser.add_argument("-v", dest="_verbose", action="count", default=0) parser.add_argument("--tray", action="store_true") parser.add_argument("--log", action="store_true") - # undocumented debug args + # debug options parser.add_argument( - "--debug-ws", dest="_debug_ws", action="store_true", help=argparse.SUPPRESS + "--debug-ws", dest="_debug_ws", action="store_true" ) parser.add_argument( - "--debug-gql", dest="_debug_gql", action="store_true", help=argparse.SUPPRESS + "--debug-gql", dest="_debug_gql", action="store_true" ) args = parser.parse_args(namespace=ParsedArgs()) # load settings diff --git a/manual.txt b/manual.txt index 7fefdbfa..d74b5d40 100644 --- a/manual.txt +++ b/manual.txt @@ -12,8 +12,15 @@ Available command line arguments: • --log Enables logging of runtime information into a 'log.txt' file. Verbosity level of this logging matches the level set by `-v`. + • --version - Show application version information + Show application version information and exit +• --debug-gql + Show GQL debug info +• --debug-ws + Show WS debug info +• --help, -h + Show help prompt and exit Note: Additional settings are available within the application GUI. diff --git a/patch_notes.txt b/patch_notes.txt new file mode 100644 index 00000000..d9c35b31 --- /dev/null +++ b/patch_notes.txt @@ -0,0 +1,56 @@ +## v15.6.0 + +1.6.2024 +- Fixed bug where long cmapaign names caused a crash when trying to update tray description +- Fixed `UnboundLocalError` crash due to wrong indentation + +30.5.2024 +- updated **Arabic**, **Turkish**, **Simplified Chinese** and **English** translation as well as corresponding credits + +28.5.2024 +- updated **Italian**, **Polish**, **Turkish** and **Ukrainian** translation as well as corresponding credits + + + +## v15.5.0 + +25.5.2024 +- Added ability to prioritize by Campaign end date (made by @jaredkotoff) +- Updated **Simplified and Traditional Chinese**, **Turkish** and **Ukrainian** translation as well as corresponding credits + + + +## v15.4.0 + +23.5.2024 +- Fixed crash on Linux caused by trying to apply a Windows-exclusive Tkinter theme +- Updated **English**, **German**, **Czech**, **Spanish** and **Russian** translation as well as corresponding credits for dark themes and potential future Campaign prioritization by end date + + + +## v15.3.0 + +22.5.2024 +- Completed dark mode 🎉 + +20.5.2024 +- Added incomplete dark mode + + + +## v15.2.0 + +19.5.2024 +- Updated **French** translation as well as corresponding credits + +18.5.2024 +- Updated **Russian**, **Ukrainian** and **Traditional Chinese** translation as well as corresponding credits +- Various changes to github workflows + + + +## v15.1.0 + +17.5.2024 +- Updated **Italian**, **Simplified Chinese** and **Spanish** translation as well as corresponding credits +- Various changes to github workflows diff --git a/requirements.txt b/requirements.txt index 827d2d96..f78481fc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,6 +2,7 @@ aiohttp>=3.9,<4.0 Pillow pystray PyGObject<3.47; sys_platform == "linux" # required for better system tray support on Linux +validators # environment-dependent dependencies pywin32; sys_platform == "win32" diff --git a/run_dev.bat b/run_dev.bat index 8652562c..0f183668 100644 --- a/run_dev.bat +++ b/run_dev.bat @@ -6,6 +6,10 @@ set /p "choice=Start with a console? (y/n) " if "%choice%"=="y" ( set "exepath=%dirpath%\env\scripts\python" ) else ( - set "exepath=%dirpath%\env\scripts\pythonw" + if "%choice%"=="" ( + set "exepath=%dirpath%\env\scripts\python" + ) else ( + set "exepath=%dirpath%\env\scripts\pythonw" + ) ) start "TwitchDropsMiner" "%exepath%" "%dirpath%\main.py" diff --git a/settings.py b/settings.py index 1e0ee1a7..eb0a0a16 100644 --- a/settings.py +++ b/settings.py @@ -14,10 +14,12 @@ class SettingsFile(TypedDict): proxy: URL language: str + dark_theme: bool autostart: bool exclude: set[str] priority: list[str] priority_only: bool + prioritize_by_ending_soonest: bool autostart_tray: bool connection_quality: int tray_notifications: bool @@ -27,8 +29,10 @@ class SettingsFile(TypedDict): "proxy": URL(), "priority": [], "exclude": set(), + "dark_theme": False, "autostart": False, "priority_only": True, + "prioritize_by_ending_soonest": False, "autostart_tray": False, "connection_quality": 1, "language": DEFAULT_LANG, @@ -48,10 +52,12 @@ class Settings: # from settings file proxy: URL language: str + dark_theme: bool autostart: bool exclude: set[str] priority: list[str] priority_only: bool + prioritize_by_ending_soonest: bool autostart_tray: bool connection_quality: int tray_notifications: bool diff --git a/translate.py b/translate.py index 227c0e8c..acb929eb 100644 --- a/translate.py +++ b/translate.py @@ -4,8 +4,9 @@ from typing import Any, TypedDict, TYPE_CHECKING from exceptions import MinerException -from utils import json_load, json_save -from constants import IS_PACKAGED, LANG_PATH, DEFAULT_LANG +from utils import json_load +from constants import LANG_PATH, DEFAULT_LANG +import json if TYPE_CHECKING: from typing_extensions import NotRequired @@ -166,7 +167,9 @@ class GUISettingsGeneral(TypedDict): tray: str tray_notifications: str priority_only: str + prioritize_by_ending_soonest: str proxy: str + dark_theme: str class GUISettings(TypedDict): @@ -214,211 +217,14 @@ class Translation(TypedDict): error: ErrorMessages gui: GUIMessages - -default_translation: Translation = { - "english_name": "English", - "status": { - "terminated": "\nApplication Terminated.\nClose the window to exit the application.", - "watching": "Watching: {channel}", - "goes_online": "{channel} goes ONLINE, switching...", - "goes_offline": "{channel} goes OFFLINE, switching...", - "claimed_drop": "Claimed drop: {drop}", - "claimed_points": "Claimed bonus points: {points}", - "earned_points": "Earned points for watching: {points}, total: {balance}", - "no_channel": "No available channels to watch. Waiting for an ONLINE channel...", - "no_campaign": "No active campaigns to mine drops for. Waiting for an active campaign...", - }, - "login": { - "unexpected_content": ( - "Unexpected content type returned, usually due to being redirected. " - "Do you need to login for internet access?" - ), - "chrome": { - "startup": "Opening Chrome...", - "login_to_complete": ( - "Complete the login procedure manually by pressing the Login button again." - ), - "no_token": "No authorization token could be found.", - "closed_window": ( - "Chrome window was closed before the login procedure could complete." - ), - }, - "error_code": "Login error code: {error_code}", - "incorrect_login_pass": "Incorrect username or password.", - "incorrect_email_code": "Incorrect email code.", - "incorrect_twofa_code": "Incorrect 2FA code.", - "email_code_required": "Email code required. Check your email.", - "twofa_code_required": "2FA token required.", - }, - "error": { - "captcha": "Your login attempt was denied by CAPTCHA.\nPlease try again in 12+ hours.", - "site_down": "Twitch is down, retrying in {seconds} seconds...", - "no_connection": "Cannot connect to Twitch, retrying in {seconds} seconds...", - }, - "gui": { - "output": "Output", - "status": { - "name": "Status", - "idle": "Idle", - "exiting": "Exiting...", - "terminated": "Terminated", - "cleanup": "Cleaning up channels...", - "gathering": "Gathering channels...", - "switching": "Switching the channel...", - "fetching_inventory": "Fetching inventory...", - "fetching_campaigns": "Fetching campaigns...", - "adding_campaigns": "Adding campaigns to inventory... {counter}", - }, - "tabs": { - "main": "Main", - "inventory": "Inventory", - "settings": "Settings", - "help": "Help", - }, - "tray": { - "notification_title": "Mined Drop", - "minimize": "Minimize to Tray", - "show": "Show", - "quit": "Quit", - }, - "login": { - "name": "Login Form", - "labels": "Status:\nUser ID:", - "logged_in": "Logged in", - "logged_out": "Logged out", - "logging_in": "Logging in...", - "required": "Login required", - "request": "Please log in to continue.", - "username": "Username", - "password": "Password", - "twofa_code": "2FA code (optional)", - "button": "Login", - }, - "websocket": { - "name": "Websocket Status", - "websocket": "Websocket #{id}:", - "initializing": "Initializing...", - "connected": "Connected", - "disconnected": "Disconnected", - "connecting": "Connecting...", - "disconnecting": "Disconnecting...", - "reconnecting": "Reconnecting...", - }, - "progress": { - "name": "Campaign Progress", - "drop": "Drop:", - "game": "Game:", - "campaign": "Campaign:", - "remaining": "{time} remaining", - "drop_progress": "Progress:", - "campaign_progress": "Progress:", - }, - "channels": { - "name": "Channels", - "switch": "Switch", - "load_points": "Load Points", - "online": "ONLINE ✔", - "pending": "OFFLINE ⏳", - "offline": "OFFLINE ❌", - "headings": { - "channel": "Channel", - "status": "Status", - "game": "Game", - "viewers": "Viewers", - "points": "Points", - }, - }, - "inventory": { - "filter": { - "name": "Filter", - "show": "Show:", - "not_linked": "Not linked", - "upcoming": "Upcoming", - "expired": "Expired", - "excluded": "Excluded", - "finished": "Finished", - "refresh": "Refresh", - }, - "status": { - "linked": "Linked ✔", - "not_linked": "Not Linked ❌", - "active": "Active ✔", - "upcoming": "Upcoming ⏳", - "expired": "Expired ❌", - "claimed": "Claimed ✔", - "ready_to_claim": "Ready to claim ⏳", - }, - "starts": "Starts: {time}", - "ends": "Ends: {time}", - "allowed_channels": "Allowed Channels:", - "all_channels": "All", - "and_more": "and {amount} more...", - "percent_progress": "{percent} of {minutes} minutes", - "minutes_progress": "{minutes} minutes", - }, - "settings": { - "general": { - "name": "General", - "autostart": "Autostart: ", - "tray": "Autostart into tray: ", - "tray_notifications": "Tray notifications: ", - "priority_only": "Priority Only: ", - "proxy": "Proxy (requires restart):", - }, - "game_name": "Game name", - "priority": "Priority", - "exclude": "Exclude", - "reload": "Reload", - "reload_text": "Most changes require a reload to take an immediate effect: ", - }, - "help": { - "links": { - "name": "Useful Links", - "inventory": "See Twitch inventory", - "campaigns": "See all campaigns and manage account links", - }, - "how_it_works": "How It Works", - "how_it_works_text": ( - "Every ~60 seconds, the application sends a \"minute watched\" event " - "to the channel that's currently being watched - this is enough " - "to advance the drops. Note that this completely bypasses the need to download " - "any actual stream video and sound. " - "To keep the status (ONLINE or OFFLINE) of the channels up-to-date, " - "there's a websocket connection estabilished that receives events about streams " - "going up or down, or updates regarding the current amount of viewers." - ), - "getting_started": "Getting Started", - "getting_started_text": ( - "1. Login into the application.\n" - "2. Ensure your Twitch account is linked to all campaigns " - "you're interested in mining.\n" - "3. If you're interested in just mining everything, " - "uncheck \"Priority only\" and press on \"Reload\".\n" - "4. If you want to mine specific games first, use the \"Priority\" list " - "to setup an ordered list of games of your choice. Games from the top of the list " - "will be attempted to be mined first, before the ones lower down the list.\n" - "5. Keep the \"Priority only\" option checked, to avoid mining games " - "that are not on the priority list. Or not - it's up to you.\n" - "6. Use the \"Exclude\" list to tell the application " - "which games should never be mined.\n" - "7. Changing the contents of either of the lists, or changing the state " - "of the \"Priority only\" option, requires you to press on \"Reload\" " - "for the changes to take an effect." - ), - }, - }, -} - +with open(LANG_PATH.joinpath(f"{DEFAULT_LANG}.json"), 'r', encoding='utf-8') as file: + default_translation: Translation = json.load(file) class Translator: def __init__(self) -> None: self._langs: list[str] = [] # start with (and always copy) the default translation self._translation: Translation = default_translation.copy() - # if we're in dev, update the template English.json file - if not IS_PACKAGED: - default_langpath = LANG_PATH.joinpath(f"{DEFAULT_LANG}.json") - json_save(default_langpath, default_translation) self._translation["language_name"] = DEFAULT_LANG # load available translation names for filepath in LANG_PATH.glob("*.json"): diff --git a/twitch.py b/twitch.py index 89aed302..505cd59d 100644 --- a/twitch.py +++ b/twitch.py @@ -34,6 +34,7 @@ ) from exc raise +from cache import CurrentSeconds from translate import _ from gui import GUIManager from channel import Channel @@ -746,14 +747,17 @@ def get_priority(self, channel: Channel) -> int: Return a priority number for a given channel. Higher number, higher priority. - Priority 0 is given to channels streaming a game not on the priority list. - Priority -1 is given to OFFLINE channels, or channels streaming no particular games. + Priority requested games are > 0 + Non-priority games are < 0 + (maxsize - 1) Priority is given to OFFLINE channels, or channels streaming no particular games. + (maxsize - 2) Priority is given to channels streaming games without campaigns. """ if (game := channel.game) is None: # None when OFFLINE or no game set - return -1 + return -(sys.maxsize - 1) elif game not in self.wanted_games: - return 0 + # Any channel thats is filtered out by filter_campaigns() + return -(sys.maxsize - 2) return self.wanted_games[game] @staticmethod @@ -825,22 +829,21 @@ async def _run(self): # figure out which games we want self.wanted_games.clear() priorities = self.gui.settings.priorities() - exclude = self.settings.exclude - priority = self.settings.priority - priority_only = self.settings.priority_only - next_hour = datetime.now(timezone.utc) + timedelta(hours=1) - for campaign in self.inventory: + prioritize_by_ending_soonest = self.settings.prioritize_by_ending_soonest + campaigns = self.inventory + filtered_campaigns = list(filter(self.filter_campaigns, campaigns)) + for i, campaign in enumerate(filtered_campaigns): game = campaign.game - if ( - game not in self.wanted_games # isn't already there - and game.name not in exclude # and isn't excluded - # and isn't excluded by priority_only - and (not priority_only or game.name in priority) - # and can be progressed within the next hour - and campaign.can_earn_within(next_hour) - ): - # non-excluded games with no priority are placed last, below priority ones - self.wanted_games[game] = priorities.get(game.name, 0) + # get users priority preference + game_priority = priorities.get(game.name, 0) + if (game_priority): + if (prioritize_by_ending_soonest): + # list is sorted by end_at so this keeps them in order + self.wanted_games[game] = len(filtered_campaigns) - i + else: + self.wanted_games[game] = game_priority + else: + self.wanted_games[game] = -i full_cleanup = True self.restart_watching() self.change_state(State.CHANNELS_CLEANUP) @@ -1047,7 +1050,7 @@ async def _watch_loop(self) -> NoReturn: if not succeeded: # this usually means the campaign expired in the middle of mining # NOTE: the maintenance task should switch the channel right after this happens - await self._watch_sleep(60) + await self._watch_sleep(interval) continue last_watch = time() self._drop_update = asyncio.Future() @@ -1101,13 +1104,15 @@ async def _watch_loop(self) -> NoReturn: # NOTE: get_active_drop uses the watching channel by default, # so there's no point to pass it here if (drop := self.get_active_drop()) is not None: - drop.bump_minutes() - drop.display() - drop_text = ( - f"{drop.name} ({drop.campaign.game}, " - f"{drop.current_minutes}/{drop.required_minutes})" - ) - logger.log(CALL, f"Drop progress from active search: {drop_text}") + current_seconds = CurrentSeconds.get_current_seconds() + if current_seconds < 1: + drop.bump_minutes() + drop.display() + drop_text = ( + f"{drop.name} ({drop.campaign.game}, " + f"{drop.current_minutes}/{drop.required_minutes})" + ) + logger.log(CALL, f"Drop progress from active search: {drop_text}") else: logger.log(CALL, "No active drop could be determined") await self._watch_sleep(last_watch + interval - time()) @@ -1614,6 +1619,23 @@ async def fetch_campaigns( } return self._merge_data(campaign_ids, fetched_data) + def filter_campaigns(self, campaign: list[DropsCampaign]): + exclude = self.settings.exclude + priority = self.settings.priority + priority_only = self.settings.priority_only + game = campaign.game + next_hour = datetime.now(timezone.utc) + timedelta(hours=1) + if ( + game not in self.wanted_games # isn't already there + and game.name not in exclude # and isn't excluded + # and isn't excluded by priority_only + and (not priority_only or game.name in priority) + # and can be progressed within the next hour + and campaign.can_earn_within(next_hour) + ): + return True + return False + async def fetch_inventory(self) -> None: status_update = self.gui.status.update status_update(_("gui", "status", "fetching_inventory"))