diff --git a/data/com.github.tkashkin.gamehub.gschema.xml.in b/data/com.github.tkashkin.gamehub.gschema.xml.in
index 134b2287..0a4b3ce2 100644
--- a/data/com.github.tkashkin.gamehub.gschema.xml.in
+++ b/data/com.github.tkashkin.gamehub.gschema.xml.in
@@ -146,6 +146,21 @@
+
+
+ true
+ Is EpicGames enabled
+
+
+ false
+ Is user authenticated
+
+
+ ''
+ EpicGames access sid
+
+
+
true
@@ -221,6 +236,14 @@
'~/Games/itch'
itch.io games directory
+
+ 'legendary'
+ Legendary client command
+
+
+ '~/legendary'
+ EpicGames games directory
+
diff --git a/data/icons/icons.gresource.xml b/data/icons/icons.gresource.xml
index bf13ca6a..334ba166 100644
--- a/data/icons/icons.gresource.xml
+++ b/data/icons/icons.gresource.xml
@@ -3,6 +3,7 @@
symbolic/sources/sources-all.svg
symbolic/sources/steam.svg
+ symbolic/sources/epicgames.svg
symbolic/sources/gog.svg
symbolic/sources/humble.svg
symbolic/sources/humble-trove.svg
diff --git a/data/icons/symbolic/sources/epicgames.svg b/data/icons/symbolic/sources/epicgames.svg
new file mode 100644
index 00000000..f618e2a2
--- /dev/null
+++ b/data/icons/symbolic/sources/epicgames.svg
@@ -0,0 +1,30 @@
+
+
\ No newline at end of file
diff --git a/po/LINGUAS b/po/LINGUAS
index 41bc1cd4..f8fd6bd2 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -22,3 +22,4 @@ zh_CN
zh_HK
zh_TW
mr
+bn_BD
diff --git a/po/bn_BD.po b/po/bn_BD.po
new file mode 100644
index 00000000..dea14314
--- /dev/null
+++ b/po/bn_BD.po
@@ -0,0 +1,1800 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the com.github.tkashkin.gamehub package.
+# Oymate , 2020.
+msgid ""
+msgstr ""
+"Project-Id-Version: com.github.tkashkin.gamehub\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-01-26 06:40+0300\n"
+"PO-Revision-Date: 2020-05-04 12:11+0000\n"
+"Last-Translator: Oymate \n"
+"Language-Team: Bengali (Bangladesh) \n"
+"Language: bn_BD\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 4.1-dev\n"
+
+#: src/app.vala:91
+msgid "Show help"
+msgstr "সহায়তা দেখান"
+
+#: src/app.vala:92
+msgid "Show application version and exit"
+msgstr "অ্যাপ্লিকেশন সংস্করণ দেখান এবং বের হন"
+
+#: src/app.vala:93
+msgid "Restart with GDB debugger attached"
+msgstr "সংযুক্ত জিডিবি ডিবাগার যুক্ত করে পুনরায় চালু করুন"
+
+#: src/app.vala:94
+msgid "Show full GDB backtrace"
+msgstr "সম্পূর্ণ জিডিবি ব্যাকট্রেস দেখান"
+
+#: src/app.vala:95
+msgid "Treat fatal errors as criticals and crash application"
+msgstr ""
+"ভয়ঙ্কর ত্রুটিগুলোকে মারাত্বক বলে বিবেচনা করুন এবং অ্যাপ্লিকেশন ক্র্যাশ করুন"
+
+#: src/app.vala:99
+msgid "Show main window"
+msgstr "প্রধান উইন্ডোটি দেখান"
+
+#: src/app.vala:100
+msgid "Show application settings dialog"
+msgstr "অ্যাপ্লিকেশন সেটিংস ডায়ালগ দেখান"
+
+#: src/app.vala:101
+msgid "Show about dialog"
+msgstr "অ্যাপ্লিকেশন সম্পর্কে ডায়লগ দেখান"
+
+#: src/app.vala:102
+msgid "Maximum number of background worker threads"
+msgstr "সর্বোচ্চ সংখ্যক ব্যাকগ্রাউন্ড কার্যকর থ্রেড"
+
+#: src/app.vala:106
+msgid "Run game"
+msgstr "গেম চালান"
+
+#: src/app.vala:107
+msgid "Show compatibility options dialog"
+msgstr "উপযুক্ততার অপশন ডায়ালগ দেখান"
+
+#: src/app.vala:108
+msgid "Open game details"
+msgstr "গেমের বিস্তারিত খুলুন"
+
+#: src/app.vala:109
+msgid "Open game properties"
+msgstr ""
+
+#: src/app.vala:113
+msgid "Enable debug logging"
+msgstr ""
+
+#: src/app.vala:114
+msgid ""
+"Log authentication process and sensitive information like authentication "
+"tokens"
+msgstr ""
+
+#: src/app.vala:115
+msgid "Log download manager"
+msgstr ""
+
+#: src/app.vala:116
+msgid "Log background workers start/stop"
+msgstr ""
+
+#: src/app.vala:117
+msgid "Disable log messages filtering"
+msgstr ""
+
+#: src/app.vala:118
+msgid "Verbose logging"
+msgstr ""
+
+#: src/app.vala:247
+msgid "Game Options:"
+msgstr ""
+
+#: src/app.vala:247
+msgid "Show game options help"
+msgstr ""
+
+#: src/app.vala:255
+msgid "Logging Options:"
+msgstr ""
+
+#: src/app.vala:255
+msgid "Show logging options help"
+msgstr ""
+
+#: src/data/Runnable.vala:110 src/data/Runnable.vala:112
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:270
+#: src/ui/dialogs/GamePropertiesDialog.vala:172
+msgid "Select executable"
+msgstr ""
+
+#: src/data/Runnable.vala:110 src/data/Runnable.vala:112
+#: src/data/Runnable.vala:181 src/ui/views/GamesView/GamesView.vala:330
+#: src/ui/widgets/FileChooserEntry.vala:55
+#: src/ui/widgets/FileChooserEntry.vala:57
+msgid "Select"
+msgstr ""
+
+#: src/data/Runnable.vala:110 src/data/Runnable.vala:112
+#: src/data/Runnable.vala:180 src/ui/widgets/FileChooserEntry.vala:55
+#: src/ui/widgets/FileChooserEntry.vala:57
+msgid "Cancel"
+msgstr ""
+
+#: src/data/Runnable.vala:166 src/ui/widgets/FileChooserEntry.vala:49
+msgid "Select directory"
+msgstr ""
+
+#: src/data/Runnable.vala:619
+#, c-format
+msgid "Part %1$u of %2$u: %3$s"
+msgstr ""
+
+#: src/data/Runnable.vala:642 src/ui/dialogs/CorruptedInstallerDialog.vala:48
+#, c-format
+msgid "%s: corrupted installer"
+msgstr ""
+
+#: src/data/Runnable.vala:643
+#, c-format
+msgid "Checksum mismatch in %s"
+msgstr ""
+
+#: src/data/Runnable.vala:657 src/ui/dialogs/CorruptedInstallerDialog.vala:126
+msgid "Show file"
+msgstr ""
+
+#: src/data/Runnable.vala:658 src/ui/dialogs/CorruptedInstallerDialog.vala:132
+#: src/ui/views/GamesView/GameContextMenu.vala:167
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:241
+#: src/ui/widgets/TagRow.vala:146
+msgid "Remove"
+msgstr ""
+
+#: src/data/Runnable.vala:659 src/ui/dialogs/CorruptedInstallerDialog.vala:128
+msgid "Backup"
+msgstr ""
+
+#: src/data/Runnable.vala:778
+#, c-format
+msgid "%s: cannot detect main executable"
+msgstr ""
+
+#: src/data/Runnable.vala:779
+msgid ""
+"Main executable file for this game cannot be detected automatically.\n"
+"Please set main executable in game's properties."
+msgstr ""
+
+#: src/data/Runnable.vala:908
+msgctxt "platform"
+msgid "Emulated"
+msgstr ""
+
+#: src/data/Game.vala:625
+msgctxt "status"
+msgid "Running"
+msgstr ""
+
+#: src/data/Game.vala:628
+msgctxt "status"
+msgid "Installed"
+msgstr ""
+
+#: src/data/Game.vala:629
+msgctxt "status"
+msgid "Installing"
+msgstr ""
+
+#: src/data/Game.vala:630
+msgctxt "status"
+msgid "Verifying installer integrity"
+msgstr ""
+
+#: src/data/Game.vala:631
+msgctxt "status"
+msgid "Download started"
+msgstr ""
+
+#: src/data/Game.vala:633
+msgctxt "status"
+msgid "Not installed"
+msgstr ""
+
+#: src/data/Game.vala:643
+msgctxt "status_header"
+msgid "Installed"
+msgstr ""
+
+#: src/data/Game.vala:644
+msgctxt "status_header"
+msgid "Installing"
+msgstr ""
+
+#: src/data/Game.vala:646
+msgctxt "status_header"
+msgid "Downloading"
+msgstr ""
+
+#: src/data/Game.vala:648
+msgctxt "status_header"
+msgid "Not installed"
+msgstr ""
+
+#: src/data/GameSource.vala:31
+#, c-format
+msgid "%s games"
+msgstr ""
+
+#: src/data/sources/steam/Steam.vala:43
+msgid "Your SteamID will be read from Steam configuration file"
+msgstr ""
+
+#: src/data/sources/steam/Steam.vala:46
+msgid ""
+"Steam config file not found.\n"
+"Login into your account in Steam client and return to GameHub"
+msgstr ""
+
+#: src/data/sources/gog/GOGGame.vala:983
+#, c-format
+msgid "DLC: %s"
+msgstr ""
+
+#: src/data/sources/humble/HumbleGame.vala:343
+#, c-format
+msgid "%s: no available installers"
+msgstr ""
+
+#: src/data/sources/humble/HumbleGame.vala:344
+msgid ""
+"Cannot get Trove download URL.\n"
+"Make sure your Humble Monthly subscription is active."
+msgstr ""
+
+#: src/data/sources/itch/ItchDownloader.vala:192
+#, c-format
+msgctxt "itch_dl_status"
+msgid "%s left;"
+msgstr ""
+
+#: src/data/sources/itch/ItchDownloader.vala:195
+#, c-format
+msgctxt "itch_dl_status"
+msgid "%d%%"
+msgstr ""
+
+#: src/data/sources/itch/ItchDownloader.vala:198
+#, c-format
+msgctxt "itch_dl_status"
+msgid "(%1$s / %2$s)"
+msgstr ""
+
+#: src/data/sources/itch/ItchDownloader.vala:201
+#, c-format
+msgctxt "itch_dl_status"
+msgid "[%s/s]"
+msgstr ""
+
+#: src/data/sources/user/User.vala:30
+msgid "User games"
+msgstr ""
+
+#: src/data/db/tables/Tags.vala:225
+msgctxt "tag"
+msgid "Favorites"
+msgstr ""
+
+#: src/data/db/tables/Tags.vala:226
+msgctxt "tag"
+msgid "Not installed"
+msgstr ""
+
+#: src/data/db/tables/Tags.vala:227
+msgctxt "tag"
+msgid "Installed"
+msgstr ""
+
+#: src/data/db/tables/Tags.vala:228
+msgctxt "tag"
+msgid "Hidden"
+msgstr ""
+
+#: src/data/compat/CustomScript.vala:60
+msgid "Edit script"
+msgstr ""
+
+#: src/data/compat/CustomScript.vala:60
+msgid "Edit custom script"
+msgstr ""
+
+#: src/data/compat/Innoextract.vala:55
+#, c-format
+msgid ""
+"Innoextract %1$s is not supported and may not be able to extract some "
+"games correctly.\n"
+"Install innoextract %2$s or newer."
+msgstr ""
+
+#: src/data/compat/WineWrap.vala:61
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:242
+#: src/ui/dialogs/CompatRunDialog.vala:102
+#: src/ui/views/GamesView/GameContextMenu.vala:53
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:234
+msgid "Run"
+msgstr ""
+
+#: src/data/compat/WineWrap.vala:64
+msgid "Show WineWrap menu"
+msgstr ""
+
+#: src/data/compat/WineWrap.vala:67 src/data/compat/Proton.vala:122
+#: src/data/compat/Wine.vala:83
+msgid "Kill apps in prefix"
+msgstr ""
+
+#: src/data/compat/Proton.vala:47
+msgid "Proton prefix"
+msgstr ""
+
+#: src/data/compat/Proton.vala:110 src/data/compat/Wine.vala:71
+msgid "Open prefix directory"
+msgstr ""
+
+#: src/data/compat/Proton.vala:113 src/data/compat/Wine.vala:74
+msgid "Run winecfg"
+msgstr ""
+
+#: src/data/compat/Proton.vala:116 src/data/compat/Wine.vala:77
+msgid "Run winetricks"
+msgstr ""
+
+#: src/data/compat/Proton.vala:119 src/data/compat/Wine.vala:80
+msgid "Run taskmgr"
+msgstr ""
+
+#: src/data/compat/Wine.vala:53
+msgid "Wine prefix"
+msgstr ""
+
+#: src/data/compat/Wine.vala:55
+msgid "Environment variables"
+msgstr ""
+
+#: src/data/compat/Wine.vala:60
+msgid "InnoSetup default options"
+msgstr ""
+
+#: src/data/compat/RetroArch.vala:53
+msgid "Libretro core file"
+msgstr ""
+
+#: src/data/compat/CustomEmulator.vala:43
+msgid "Custom emulator"
+msgstr ""
+
+#: src/data/compat/CustomEmulator.vala:48
+msgid "Emulator"
+msgstr ""
+
+#: src/data/compat/CustomEmulator.vala:49
+msgid "Launch in game directory"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:440
+msgctxt "status_header"
+msgid "Favorites"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:445
+#, c-format
+msgctxt "status_header"
+msgid "%s: Favorites"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:491
+msgid "Merging games"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:504
+#, c-format
+msgid "Merging games from %s"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:551
+#, c-format
+msgid "Loading games from %s"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:678
+msgctxt "sort_mode"
+msgid "By name"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:679
+msgctxt "sort_mode"
+msgid "By last launch"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:680
+msgctxt "sort_mode"
+msgid "By playtime"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:705
+msgctxt "group_mode"
+msgid "Do not group"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:706
+msgctxt "group_mode"
+msgid "By status"
+msgstr ""
+
+#: src/data/adapters/GamesAdapter.vala:707
+msgctxt "group_mode"
+msgid "By source"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:151
+#: src/data/providers/data/IGDB.vala:431
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:217
+msgid "Default"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:158
+#: src/data/providers/data/IGDB.vala:438
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:225
+msgid "Restore default API key"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:169
+#: src/data/providers/data/IGDB.vala:449
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:108
+msgid "API key"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:177
+#: src/data/providers/data/IGDB.vala:457
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:59
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:53
+msgid "Generate key"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:208
+msgctxt "imagesource_steamgriddb_image_property"
+msgid "Style"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:209
+msgctxt "imagesource_steamgriddb_image_property"
+msgid "Score"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:213
+msgctxt "imagesource_steamgriddb_image_property"
+msgid "Author"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:225
+msgctxt "imagesource_steamgriddb_image_style"
+msgid "Alternate"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:226
+msgctxt "imagesource_steamgriddb_image_style"
+msgid "Blurred"
+msgstr ""
+
+#. TRANSLATORS: Flat / Material Design image style. Probably should not be translated
+#: src/data/providers/images/SteamGridDB.vala:228
+msgctxt "imagesource_steamgriddb_image_style"
+msgid "Material"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:229
+msgctxt "imagesource_steamgriddb_image_style"
+msgid "No logo"
+msgstr ""
+
+#: src/data/providers/images/SteamGridDB.vala:230
+msgctxt "imagesource_steamgriddb_image_style"
+msgid "White logo"
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:147
+msgid ""
+"Monthly IGDB request quota has been reached. Set your own API key to use "
+"IGDB data or disable IGDB."
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:148
+#: src/ui/dialogs/SettingsDialog/SettingsDialog.vala:40
+#: src/ui/views/WelcomeView.vala:53 src/ui/views/WelcomeView.vala:78
+#: src/ui/views/GamesView/GamesView.vala:230
+#: src/ui/views/GamesView/GamesView.vala:629
+msgid "Settings"
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:356
+msgctxt "igdb_related_link"
+msgid "Official website"
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:469
+msgctxt "igdb_preferred_description"
+msgid "When game has description, show description"
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:476
+msgctxt "igdb_preferred_description"
+msgid "of game"
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:477
+msgctxt "igdb_preferred_description"
+msgid "from IGDB"
+msgstr ""
+
+#: src/data/providers/data/IGDB.vala:478
+msgctxt "igdb_preferred_description"
+msgid "both"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/SettingsDialog.vala:65
+msgid "Some settings will be applied after application restart"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/SettingsDialog.vala:71
+msgid "Games directory contains space. It may cause problems for some games"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:36
+msgid "Interface"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:37
+msgid "Appearance"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:38
+msgid "General interface settings"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:48
+msgid "Dark theme"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:53
+msgctxt "icon_style"
+msgid "Theme-based"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:54
+msgctxt "icon_style"
+msgid "Symbolic"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:55
+msgctxt "icon_style"
+msgid "Colored"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:57
+msgctxt "icon_style"
+msgid "Icon style"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:84
+msgid "Game card"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:86
+msgid "Show platform icons"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:99
+msgctxt "grid_size"
+msgid "Card size"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:117
+msgctxt "grid_size_preset"
+msgid "Presets"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:139
+msgid "Games list: installed"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:140
+msgid "Games list: not installed"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:142
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:146
+msgctxt "list_style"
+msgid "Show icon"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:143
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:147
+msgctxt "list_style"
+msgid "Bold title"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:144
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:148
+msgctxt "list_style"
+msgid "Show status"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:149
+msgctxt "list_style"
+msgid "Dim"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:151
+msgid "Grid options"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:152
+msgid "List options"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Behavior.vala:31
+msgid "Behavior"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Behavior.vala:32
+msgid "Behavior settings"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Behavior.vala:42
+msgid "Run games with double click"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Behavior.vala:46
+msgid "Merge games from different sources"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/ui/Behavior.vala:50
+msgid "Use imported tags"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:51
+msgid "General"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:52
+msgid "Collection"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:53
+msgid "Empty"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:65
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:85
+msgid "Collection directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:70
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:78
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:87
+msgid "Game directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:71
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:79
+msgid "Installers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:72
+#: src/ui/views/GameDetailsView/blocks/GOGDetails.vala:98
+msgid "DLC"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:73
+#: src/ui/views/GameDetailsView/blocks/GOGDetails.vala:197
+msgid "Bonus content"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:84
+msgid "Variable syntax: $var or ${var}"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:86
+msgid "Game name"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Collection.vala:88
+#: src/ui/views/GamesView/FiltersPopover.vala:127
+msgid "Platform"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:36
+msgid "Controller"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:37
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:106
+msgid "Enabled"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:53
+msgid "Focus GameHub window with Guide button"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:57
+msgid "Controllers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:89
+msgid "Move focus"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:91
+msgid "Exit"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Controller.vala:106
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:40
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:108
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:37
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:92
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:37
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:95
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:36
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:77
+msgid "Disabled"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:33
+#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:47
+#: src/ui/dialogs/GameTweaksDialog.vala:53
+#: src/ui/views/GamesView/GameContextMenu.vala:183
+msgid "Tweaks"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:34
+msgid "Tweak launch options and apply them to games automatically"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:79
+msgid ""
+"Tweaks are loaded from following directories in order\n"
+"Last tweak overrides previous tweaks with same identifiers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:83
+msgid "Click to open"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:93
+#, c-format
+msgid "Tweaks are loaded from %1$s and %2$d more directories (?)"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:38
+msgid "Game sources"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:59
+msgid "Steam API keys have limited number of uses per day"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:63
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:57
+msgid "Installation directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:112
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:176
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:81
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:34
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:75
+msgid "Not installed"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:116
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:96
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:99
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:85
+msgid "Not authenticated"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:120
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:101
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:89
+#, c-format
+msgid "Authenticated as %s"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:120
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:101
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:103
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:89
+msgid "Authenticated"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:183
+#: src/ui/dialogs/InstallDialog.vala:53 src/ui/dialogs/InstallDialog.vala:111
+#: src/ui/views/GamesView/GameContextMenu.vala:80
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:143
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:233
+#: src/ui/widgets/TweaksList.vala:95
+msgid "Install"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Steam.vala:236
+msgid "Steam API key"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:50
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:54
+#: src/ui/dialogs/SettingsDialog/pages/sources/Itch.vala:48
+msgid "Games directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/GOG.vala:59
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:63
+msgid "Logout"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/sources/Humble.vala:50
+msgid "Load games from Humble Trove"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:33
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:45
+msgid "Emulators"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:45
+msgid "Libretro core directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:46
+msgid "Libretro core info directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:50
+msgid "Ignored libretro cores"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:54
+msgid "Ignored game file extensions"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:66
+msgid "No cores found"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/RetroArch.vala:70
+#, c-format
+msgid "%u core found"
+msgid_plural "%u cores found"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:46
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:168
+msgid "No custom emulators"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:164
+#, c-format
+msgid "%u custom emulator"
+msgid_plural "%u custom emulators"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:237
+msgid "Save"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:250
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:270
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:312
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:404
+#: src/ui/dialogs/GamePropertiesDialog.vala:168
+#: src/ui/dialogs/GamePropertiesDialog.vala:172
+#: src/ui/views/GamesView/AddGamePopover.vala:67
+#: src/ui/views/GamesView/AddGamePopover.vala:77
+#: src/ui/views/GamesView/AddGamePopover.vala:143
+msgid "Executable"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:251
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:404
+#: src/ui/views/GamesView/AddGamePopover.vala:68
+#: src/ui/views/GamesView/AddGamePopover.vala:143
+msgid "Installer"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:256
+#: src/ui/dialogs/GamePropertiesDialog.vala:64
+#: src/ui/dialogs/GamePropertiesDialog.vala:69
+#: src/ui/views/GamesView/AddGamePopover.vala:73
+msgid "Name"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:272
+#: src/ui/dialogs/GamePropertiesDialog.vala:201
+#: src/ui/views/GamesView/AddGamePopover.vala:78
+msgid "Arguments"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:276
+msgid "Variables"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:277
+msgid "Game executable"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:278
+msgid "Game arguments"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:288
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:80
+#: src/ui/views/GamesView/AddGamePopover.vala:82
+msgid "Directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:288
+msgid "Select emulator directory"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:292
+#: src/ui/dialogs/GamePropertiesDialog.vala:219
+msgid "Force compatibility mode"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:307
+msgid "Game file patterns"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:315
+msgid "Image"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:318
+msgid "Icon"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/emulators/Emulators.vala:325
+msgid ""
+"findutils-compatible glob patterns\n"
+"\n"
+"• Multiple patterns can be separated with |\n"
+"• Start pattern with ./ to match relative path\n"
+"• $basename variable will be replaced with game's executable "
+"name (without extension)"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/providers/Providers.vala:38
+msgid "Data"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/providers/Providers.vala:39
+msgid "Providers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/providers/Providers.vala:40
+msgid "Third-party data providers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/providers/Providers.vala:55
+msgid "Image providers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/providers/Providers.vala:68
+msgid "Metadata providers"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/providers/Providers.vala:137
+msgid "Open website"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:36
+msgid "About"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:71
+msgid "Copy application version and environment info"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:78
+#: src/ui/views/WelcomeView.vala:57
+msgid "All your games in one place"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:92
+msgctxt "about_link"
+msgid "Website"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:96
+msgctxt "about_link"
+msgid "Source code on GitHub"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:103
+msgctxt "about_link"
+msgid "Report a problem"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:104
+msgctxt "about_link"
+msgid "Suggest translations"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:110
+msgctxt "about_link"
+msgid "Issues"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:111
+msgctxt "about_link"
+msgid "Contributors"
+msgstr ""
+
+#. TRANSLATORS: Likely it should not be translated. GitHub Pulse is a page that shows recent repository activity: https://github.com/tkashkin/GameHub/pulse
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:114
+msgctxt "about_link"
+msgid "Pulse"
+msgstr ""
+
+#: src/ui/dialogs/SettingsDialog/pages/About.vala:115
+msgctxt "about_link"
+msgid "Forks"
+msgstr ""
+
+#: src/ui/dialogs/InstallDialog.vala:109
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:129
+msgid "Import"
+msgstr ""
+
+#: src/ui/dialogs/InstallDialog.vala:110
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:153
+msgid "Download"
+msgstr ""
+
+#: src/ui/dialogs/InstallDialog.vala:207
+msgid "Select installer"
+msgstr ""
+
+#: src/ui/dialogs/InstallDialog.vala:216
+#, c-format
+msgid "Installer size: %s"
+msgstr ""
+
+#: src/ui/dialogs/InstallDialog.vala:348
+msgid "Unknown"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:49
+#, c-format
+msgid "%s: Properties"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:84
+msgid "Images"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:126
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:160
+#: src/ui/views/GameDetailsView/blocks/Artwork.vala:62
+msgid "Download images"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:144
+msgid "Image URL"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:148
+msgid "Vertical image URL"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:157
+msgid "Icon URL"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:173
+msgid "Select working directory"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:173
+msgid "Working directory"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:214
+msgid "Compatibility"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:236
+msgid "Launch from terminal"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:252
+msgid "Copy to clipboard"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:254
+msgid "Add to Steam"
+msgstr ""
+
+#: src/ui/dialogs/GamePropertiesDialog.vala:255
+msgid "Add to the Steam library"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:53
+#, c-format
+msgid "%s: Overlays"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:71
+msgid "Overlays are disabled"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:71
+msgid ""
+"Enable overlays to manage DLCs and mods\n"
+"\n"
+"Enabling will move game to the “base“ overlay"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:77
+#: src/ui/views/GamesView/GameContextMenu.vala:175
+msgid "Overlays"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:105
+msgid "Overlay ID (directory name)"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:110
+msgid "Overlay name (optional)"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:112
+msgid "Add"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:127
+msgid "Enable overlays"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:182
+#, c-format
+msgid ""
+"Overlay usage at this path may be unsafe\n"
+"Proceed at your own risk\n"
+"\n"
+"Path: %s"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:187
+#, c-format
+msgid ""
+"Overlay usage at this path is not supported\n"
+"\n"
+"Path: %s"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:266
+msgid "Open directory"
+msgstr ""
+
+#: src/ui/dialogs/GameFSOverlaysDialog.vala:271
+msgid "Remove overlay"
+msgstr ""
+
+#: src/ui/dialogs/CompatRunDialog.vala:48
+#: src/ui/views/GamesView/GameContextMenu.vala:46
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:235
+msgid "Run with compatibility layer"
+msgstr ""
+
+#: src/ui/dialogs/CorruptedInstallerDialog.vala:71
+msgid "Corrupted installer: checksum mismatch in"
+msgstr ""
+
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:57
+#: src/ui/views/GamesView/AddGamePopover.vala:105
+msgid "Import emulated games"
+msgstr ""
+
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:75
+msgid "Select directory with emulated games"
+msgstr ""
+
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:83
+msgid "Detected games"
+msgstr ""
+
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:107
+msgid "Select all"
+msgstr ""
+
+#: src/ui/dialogs/ImportEmulatedGamesDialog.vala:115
+msgid "Select directory to import"
+msgstr ""
+
+#: src/ui/dialogs/GameTweaksDialog.vala:40
+#, c-format
+msgid "%s: Tweaks"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:52
+msgid "No enabled game sources"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:52
+msgid "Enable some game sources in settings"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:57
+msgid "Let's get started"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:71
+msgid "Skip"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:141
+msgid "Ready"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:147
+msgid "Authentication required"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:152
+msgid "Authenticating…"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:163
+#, c-format
+msgid "Install %s"
+msgstr ""
+
+#: src/ui/views/WelcomeView.vala:164
+msgid "Return to GameHub after installing"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:136
+msgid "No games"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:136
+msgid "Get some games or enable some game sources in settings"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:150
+msgid "Grid view"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:151
+msgid "List view"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:159
+msgid "All games"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:182
+msgid "Downloads"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:208
+msgid "Filters"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:216
+#: src/ui/views/GamesView/AddGamePopover.vala:84
+msgid "Add game"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:223
+msgid "Search"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:328
+msgid "Menu"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:329
+#: src/ui/views/GameDetailsView/GameDetailsView.vala:104
+msgid "Back"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:550
+#, c-format
+msgid "%u game"
+msgid_plural "%u games"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GamesView/GamesView.vala:553
+#, c-format
+msgctxt "games_view_subtitle_filtered_games"
+msgid "%1$u / %2$s"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:557
+#, c-format
+msgctxt "games_view_subtitle"
+msgid "%1$s: %2$s"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:568
+msgid "No user-added games"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:569
+msgid "Add some games using plus button"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:573
+#, c-format
+msgid "No %s games"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:574
+msgid "Get some Linux-compatible games"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:584
+#, c-format
+msgid "No games matching “%s”"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:589
+#, c-format
+msgid "No %1$s games matching “%2$s”"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:627
+msgid ""
+"No games were loaded from Steam. Set your games list privacy to public or "
+"use your own Steam API key in settings."
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:628
+msgid "Privacy"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:739
+msgid "Downloading images"
+msgstr ""
+
+#: src/ui/views/GamesView/GamesView.vala:753
+#, c-format
+msgid "Downloading image: %s"
+msgstr ""
+
+#: src/ui/views/GamesView/DownloadProgressView.vala:131
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:162
+msgid "Pause download"
+msgstr ""
+
+#: src/ui/views/GamesView/DownloadProgressView.vala:137
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:168
+msgid "Resume download"
+msgstr ""
+
+#: src/ui/views/GamesView/DownloadProgressView.vala:143
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:174
+msgid "Cancel download"
+msgstr ""
+
+#: src/ui/views/GamesView/FiltersPopover.vala:77
+msgid "Group"
+msgstr ""
+
+#: src/ui/views/GamesView/FiltersPopover.vala:102
+msgid "Sort"
+msgstr ""
+
+#: src/ui/views/GamesView/FiltersPopover.vala:234
+#: src/ui/widgets/GameTagsList.vala:58
+msgid "Tags"
+msgstr ""
+
+#: src/ui/views/GamesView/FiltersPopover.vala:353
+msgid "All platforms"
+msgstr ""
+
+#: src/ui/views/GamesView/AddGamePopover.vala:77
+msgid "Select game executable"
+msgstr ""
+
+#: src/ui/views/GamesView/AddGamePopover.vala:82
+msgid "Select game directory"
+msgstr ""
+
+#: src/ui/views/GamesView/AddGamePopover.vala:111
+msgid "Download game images"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:87
+msgid "Details"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:117
+msgctxt "game_context_menu"
+msgid "Favorite"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:121
+msgctxt "game_context_menu"
+msgid "Hidden"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:133
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:236
+msgid "Open installation directory"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:142
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:237
+msgid "Open installers collection directory"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:151
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:238
+msgid "Open bonus collection directory"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:160
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:239
+msgid "Open screenshots directory"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:167
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:167
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:241
+msgid "Uninstall"
+msgstr ""
+
+#: src/ui/views/GamesView/GameContextMenu.vala:192
+msgid "Properties"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:100
+#, c-format
+msgid "%d game selected"
+msgid_plural "%d games selected"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:144
+#, c-format
+msgid "%d game will be installed"
+msgid_plural "%d games will be installed"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:154
+#, c-format
+msgid "%d game will be downloaded"
+msgid_plural "%d games will be downloaded"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:161
+#, c-format
+msgid "Image for %d game will be searched"
+msgid_plural "Images for %d games will be searched"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:168
+#, c-format
+msgid "%d game will be uninstalled"
+msgid_plural "%d games will be uninstalled"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:174
+msgid "Refresh"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/MultipleGamesDetailsView.vala:175
+#, c-format
+msgid ""
+"%d game will be removed from database. Restart GameHub to fetch new data"
+msgid_plural ""
+"%d games will be removed from database. Restart GameHub to fetch new data"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:240
+msgid "Open store page"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/GameDetailsPage.vala:242
+msgid "Game properties"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/Playtime.vala:46
+#: src/ui/views/GameDetailsView/blocks/Playtime.vala:60
+msgid "Playtime"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/Playtime.vala:52
+msgid "Playtime (local)"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/Playtime.vala:69
+msgid "Last launch"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/Achievements.vala:46
+msgid "Achievements"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/Achievements.vala:85
+#, c-format
+msgid "Unlocked: %s"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/Achievements.vala:90
+#, c-format
+msgid "Global percentage: %g%%"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/GOGDetails.vala:77
+#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:103
+msgid "Language"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/GOGDetails.vala:80
+#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:106
+msgid "Languages"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/GOGDetails.vala:147
+#, c-format
+msgid "%u DLCs cannot be installed"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:71
+msgid "Category"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:74
+msgid "Categories"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:90
+msgid "Genre"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:93
+msgid "Genres"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:109
+msgctxt "igdb"
+msgid "Popularity"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:115
+msgctxt "igdb"
+msgid "Aggregated rating"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:116
+msgctxt "igdb"
+msgid "IGDB user rating"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:117
+msgctxt "igdb"
+msgid "Total rating"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:126
+msgctxt "igdb"
+msgid "Release date"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:133
+msgctxt "igdb"
+msgid "Platforms"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:139
+msgctxt "igdb"
+msgid "Genres"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:145
+msgctxt "igdb"
+msgid "Keywords"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:152
+msgctxt "igdb"
+msgid "Links"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:208
+#, c-format
+msgid "Based on %d rating"
+msgid_plural "Based on %d ratings"
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:290
+msgctxt "igdb"
+msgid "Summary"
+msgstr ""
+
+#: src/ui/views/GameDetailsView/blocks/IGDBInfo.vala:301
+msgctxt "igdb"
+msgid "Storyline"
+msgstr ""
+
+#: src/ui/widgets/FileChooserEntry.vala:49
+#: src/ui/widgets/FileChooserEntry.vala:55
+#: src/ui/widgets/FileChooserEntry.vala:57
+msgid "Select file"
+msgstr ""
+
+#: src/ui/widgets/ImagesDownloadPopover.vala:74
+msgid "No images"
+msgstr ""
+
+#: src/ui/widgets/ImagesDownloadPopover.vala:74
+msgid ""
+"There are no images found for this game\n"
+"Make sure game name is correct"
+msgstr ""
+
+#: src/ui/widgets/ImagesDownloadPopover.vala:94
+msgid "Search images:"
+msgstr ""
+
+#: src/ui/widgets/CompatToolPicker.vala:53
+msgid "Compatibility layer:"
+msgstr ""
+
+#: src/ui/widgets/CompatToolPicker.vala:92
+msgid "Configure"
+msgstr ""
+
+#: src/ui/widgets/GameTagsList.vala:109
+msgid "Add tag"
+msgstr ""
+
+#: src/ui/widgets/TweaksList.vala:86
+msgid "No description"
+msgstr ""
+
+#: src/ui/widgets/TweaksList.vala:124
+msgid "Edit file"
+msgstr ""
+
+#: src/utils/Utils.vala:456 src/utils/Utils.vala:464
+#, c-format
+msgctxt "time"
+msgid "%dh"
+msgstr ""
+
+#: src/utils/Utils.vala:456 src/utils/Utils.vala:464
+#, c-format
+msgctxt "time"
+msgid "%dm"
+msgstr ""
+
+#: src/utils/Utils.vala:464
+#, c-format
+msgctxt "time"
+msgid "%ds"
+msgstr ""
+
+#: src/settings/UI.vala:153
+msgctxt "grid_size_preset"
+msgid "Steam"
+msgstr ""
+
+#: src/settings/UI.vala:154
+msgctxt "grid_size_preset"
+msgid "Steam (vertical)"
+msgstr ""
+
+#: src/settings/UI.vala:155
+msgctxt "grid_size_preset"
+msgid "GOG"
+msgstr ""
+
+#: src/settings/UI.vala:156
+msgctxt "grid_size_preset"
+msgid "GOG (vertical)"
+msgstr ""
+
+#: src/settings/UI.vala:157
+msgctxt "grid_size_preset"
+msgid "Square"
+msgstr ""
+
+#: src/settings/UI.vala:158
+msgctxt "grid_size_preset"
+msgid "Custom"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:200
+msgctxt "dl_status"
+msgid "Queued"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:201
+msgctxt "dl_status"
+msgid "Starting download"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:202
+msgctxt "dl_status"
+msgid "Download started"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:203
+msgctxt "dl_status"
+msgid "Download finished"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:204
+msgctxt "dl_status"
+msgid "Download failed"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:208
+#, c-format
+msgctxt "dl_status"
+msgid "Downloading: %s"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:210
+msgctxt "dl_status"
+msgid "Downloading"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:214
+#, c-format
+msgctxt "dl_status"
+msgid "Paused: %s"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:216
+msgctxt "dl_status"
+msgid "Paused"
+msgstr ""
+
+#: src/utils/downloader/Downloader.vala:218
+msgctxt "dl_status"
+msgid "Download cancelled"
+msgstr ""
+
+#. TRANSLATORS: Download progress template. %1$d - percentage, %2$s / %3$s - downloaded portion and total file size, %4$s - download speed
+#: src/utils/downloader/Downloader.vala:262
+#, c-format
+msgctxt "dl_status"
+msgid "%1$d%% (%2$s / %3$s) [%4$s/s]"
+msgstr ""
diff --git a/po/fa.po b/po/fa.po
index efe1f987..cab1bd79 100644
--- a/po/fa.po
+++ b/po/fa.po
@@ -2,13 +2,14 @@
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the com.github.tkashkin.gamehub package.
# Goudarz Jafari , 2019.
+# Alireza Jabbari , 2020.
msgid ""
msgstr ""
"Project-Id-Version: com.github.tkashkin.gamehub\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-26 06:40+0300\n"
-"PO-Revision-Date: 2019-08-03 20:23+0000\n"
-"Last-Translator: Goudarz Jafari \n"
+"PO-Revision-Date: 2020-06-12 19:41+0000\n"
+"Last-Translator: Alireza Jabbari \n"
"Language-Team: Persian \n"
"Language: fa\n"
@@ -16,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 3.8-dev\n"
+"X-Generator: Weblate 4.1-dev\n"
#: src/app.vala:91
msgid "Show help"
@@ -28,7 +29,7 @@ msgstr "نمایش نسخه برنامه و خروج"
#: src/app.vala:93
msgid "Restart with GDB debugger attached"
-msgstr ""
+msgstr "ریاستارت همراه با عیب یاب GDB"
#: src/app.vala:94
msgid "Show full GDB backtrace"
@@ -48,7 +49,7 @@ msgstr ""
#: src/app.vala:101
msgid "Show about dialog"
-msgstr ""
+msgstr "نمایش درباره گفتوگو"
#: src/app.vala:102
msgid "Maximum number of background worker threads"
diff --git a/po/nb_NO.po b/po/nb_NO.po
index c099b7b1..36fe5f37 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: com.github.tkashkin.gamehub\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-26 06:40+0300\n"
-"PO-Revision-Date: 2020-02-01 07:50+0000\n"
+"PO-Revision-Date: 2020-05-04 12:11+0000\n"
"Last-Translator: Allan Nordhøy \n"
"Language-Team: Norwegian Bokmål \n"
@@ -18,7 +18,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 3.11-dev\n"
+"X-Generator: Weblate 4.1-dev\n"
#: src/app.vala:91
msgid "Show help"
@@ -255,9 +255,9 @@ msgstr ""
"Logg inn på din konto i Steamklienten og kom tilbake til GameHub"
#: src/data/sources/gog/GOGGame.vala:983
-#, c-format, fuzzy
+#, c-format
msgid "DLC: %s"
-msgstr "DLC: %s"
+msgstr "Nedlastbart innhold: %s"
#: src/data/sources/humble/HumbleGame.vala:343
#, c-format
@@ -612,14 +612,12 @@ msgid "Icon style"
msgstr "Ikonstil"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:84
-#, fuzzy
msgid "Game card"
-msgstr "Spillnavn"
+msgstr "Spillkort"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:86
-#, fuzzy
msgid "Show platform icons"
-msgstr "Vis plattformsikoner i rutenettvisning"
+msgstr "Vis plattformsikoner"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:99
msgctxt "grid_size"
@@ -632,14 +630,12 @@ msgid "Presets"
msgstr "Forhåndsinnstillinger"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:139
-#, fuzzy
msgid "Games list: installed"
-msgstr "Spilliste: Installert"
+msgstr "Spill-liste: Installert"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:140
-#, fuzzy
msgid "Games list: not installed"
-msgstr "Spilliste: Ikke installert"
+msgstr "Spill-liste: Ikke installert"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:142
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:146
@@ -665,14 +661,13 @@ msgid "Dim"
msgstr "Demp"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:151
-#, fuzzy
msgid "Grid options"
-msgstr "Spillegenskaper:"
+msgstr "Rutenettsegenskaper"
#: src/ui/dialogs/SettingsDialog/pages/ui/Appearance.vala:152
#, fuzzy
msgid "List options"
-msgstr "Loggføringsvalg:"
+msgstr "Listevalg"
#: src/ui/dialogs/SettingsDialog/pages/ui/Behavior.vala:31
msgid "Behavior"
@@ -794,7 +789,6 @@ msgid "Tweak launch options and apply them to games automatically"
msgstr "Tilpass oppstartsvalg og utfør dem for spill automatisk"
#: src/ui/dialogs/SettingsDialog/pages/general/Tweaks.vala:79
-#, fuzzy
msgid ""
"Tweaks are loaded from following directories in order\n"
"Last tweak overrides previous tweaks with same identifiers"
@@ -1146,14 +1140,12 @@ msgid "Icon URL"
msgstr "Ikonnettadresse"
#: src/ui/dialogs/GamePropertiesDialog.vala:173
-#, fuzzy
msgid "Select working directory"
-msgstr "Velg mappe"
+msgstr "Velg arbeidsmappe"
#: src/ui/dialogs/GamePropertiesDialog.vala:173
-#, fuzzy
msgid "Working directory"
-msgstr "Åpne mappe"
+msgstr "Arbeidsmappe"
#: src/ui/dialogs/GamePropertiesDialog.vala:214
msgid "Compatibility"
@@ -1279,9 +1271,9 @@ msgid "Select directory to import"
msgstr "Velg mappe å importere"
#: src/ui/dialogs/GameTweaksDialog.vala:40
-#, fuzzy, c-format
+#, c-format
msgid "%s: Tweaks"
-msgstr "%s: Overlag"
+msgstr "%s: Tilpasninger"
#: src/ui/views/WelcomeView.vala:52
msgid "No enabled game sources"
@@ -1308,7 +1300,6 @@ msgid "Authentication required"
msgstr "Identitetsbekreftelse kreves"
#: src/ui/views/WelcomeView.vala:152
-#, fuzzy
msgid "Authenticating…"
msgstr "Identitetsbekrefter…"
@@ -1375,16 +1366,16 @@ msgstr[0] "%u spill"
msgstr[1] "%u spill"
#: src/ui/views/GamesView/GamesView.vala:553
-#, fuzzy, c-format
+#, c-format
msgctxt "games_view_subtitle_filtered_games"
msgid "%1$u / %2$s"
-msgstr "(%1$s / %2$s)"
+msgstr "%1$u / %2$s"
#: src/ui/views/GamesView/GamesView.vala:557
-#, fuzzy, c-format
+#, c-format
msgctxt "games_view_subtitle"
msgid "%1$s: %2$s"
-msgstr "(%1$s / %2$s)"
+msgstr "%1$s: %2$s"
#: src/ui/views/GamesView/GamesView.vala:568
msgid "No user-added games"
@@ -1620,9 +1611,9 @@ msgid "Languages"
msgstr "Språk"
#: src/ui/views/GameDetailsView/blocks/GOGDetails.vala:147
-#, fuzzy, c-format
+#, c-format
msgid "%u DLCs cannot be installed"
-msgstr "%s: Skadet installasjonskandidat"
+msgstr "%u: Nedlastbart innhold kan ikke installeres"
#: src/ui/views/GameDetailsView/blocks/SteamDetails.vala:71
msgid "Category"
@@ -1737,14 +1728,12 @@ msgid "Add tag"
msgstr "Legg til etikett"
#: src/ui/widgets/TweaksList.vala:86
-#, fuzzy
msgid "No description"
-msgstr "Beskrivelse"
+msgstr "Ingen beskrivelse"
#: src/ui/widgets/TweaksList.vala:124
-#, fuzzy
msgid "Edit file"
-msgstr "Velg fil"
+msgstr "Rediger fil"
#: src/utils/Utils.vala:456 src/utils/Utils.vala:464
#, c-format
@@ -1759,10 +1748,10 @@ msgid "%dm"
msgstr "%dm"
#: src/utils/Utils.vala:464
-#, fuzzy, c-format
+#, c-format
msgctxt "time"
msgid "%ds"
-msgstr "%dt"
+msgstr "%ds"
#: src/settings/UI.vala:153
msgctxt "grid_size_preset"
@@ -1820,28 +1809,26 @@ msgid "Download failed"
msgstr "Nedlasting mislyktes"
#: src/utils/downloader/Downloader.vala:208
-#, fuzzy, c-format
+#, c-format
msgctxt "dl_status"
msgid "Downloading: %s"
-msgstr "Laster ned"
+msgstr "Laster ned: %s"
#: src/utils/downloader/Downloader.vala:210
-#, fuzzy
msgctxt "dl_status"
msgid "Downloading"
msgstr "Laster ned"
#: src/utils/downloader/Downloader.vala:214
-#, fuzzy, c-format
+#, c-format
msgctxt "dl_status"
msgid "Paused: %s"
-msgstr "Pauset: %d%% (%s / %s)"
+msgstr "Pauset: %s"
#: src/utils/downloader/Downloader.vala:216
-#, fuzzy
msgctxt "dl_status"
msgid "Paused"
-msgstr "Pause nedlasting"
+msgstr "Pauset"
#: src/utils/downloader/Downloader.vala:218
msgctxt "dl_status"
@@ -1850,10 +1837,10 @@ msgstr "Nedlasting avbrutt"
#. TRANSLATORS: Download progress template. %1$d - percentage, %2$s / %3$s - downloaded portion and total file size, %4$s - download speed
#: src/utils/downloader/Downloader.vala:262
-#, fuzzy, c-format
+#, c-format
msgctxt "dl_status"
msgid "%1$d%% (%2$s / %3$s) [%4$s/s]"
-msgstr "Laster ned: %d%% (%s / %s) [%s/s]"
+msgstr "%1$d%% (%2$s / %3$s) [%4$s/s]"
#~ msgid "Disable esync"
#~ msgstr "Skru av esync"
diff --git a/po/ru.po b/po/ru.po
index ad18fe6b..5f9d4793 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -4,22 +4,23 @@
# Automatically generated, 2018.
# Anatoliy Kashkin , 2018, 2019.
# Artem , 2020.
+# Артемий Судаков , 2020.
msgid ""
msgstr ""
"Project-Id-Version: com.github.tkashkin.gamehub\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-26 06:40+0300\n"
-"PO-Revision-Date: 2020-04-25 13:11+0000\n"
-"Last-Translator: Artem \n"
+"PO-Revision-Date: 2020-06-08 14:41+0000\n"
+"Last-Translator: Артемий Судаков \n"
"Language-Team: Russian \n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<="
-"4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.0.2-dev\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.1-dev\n"
#: src/app.vala:91
msgid "Show help"
@@ -258,7 +259,7 @@ msgstr ""
#: src/data/sources/gog/GOGGame.vala:983
#, c-format
msgid "DLC: %s"
-msgstr ""
+msgstr "DLC: %s"
#: src/data/sources/humble/HumbleGame.vala:343
#, c-format
diff --git a/src/app.vala b/src/app.vala
index 9bb6a90d..f9b67a06 100644
--- a/src/app.vala
+++ b/src/app.vala
@@ -23,6 +23,7 @@ using Gee;
using GameHub.Data;
using GameHub.Data.DB;
using GameHub.Data.Sources.Steam;
+using GameHub.Data.Sources.EpicGames;
using GameHub.Data.Sources.GOG;
using GameHub.Data.Sources.Humble;
using GameHub.Data.Sources.Itch;
@@ -141,7 +142,7 @@ namespace GameHub
ImageCache.init();
Database.create();
- GameSources = { new Steam(), new GOG(), new Humble(), new Trove(), new Itch(), new User() };
+ GameSources = { new Steam(), new EpicGames(), new GOG(), new Humble(), new Trove(), new Itch(), new User() };
Providers.ImageProviders = { new Providers.Images.Steam(), new Providers.Images.SteamGridDB(), new Providers.Images.JinxSGVI() };
Providers.DataProviders = { new Providers.Data.IGDB() };
diff --git a/src/data/GameSource.vala b/src/data/GameSource.vala
index 25b51e4e..c50abf81 100644
--- a/src/data/GameSource.vala
+++ b/src/data/GameSource.vala
@@ -21,6 +21,7 @@ using Gee;
using GameHub.Utils;
using GameHub.Data.Sources.Steam;
using GameHub.Data.Sources.GOG;
+using GameHub.Data.Sources.EpicGames;
namespace GameHub.Data
{
diff --git a/src/data/Runnable.vala b/src/data/Runnable.vala
index 20e3e694..cbaaa295 100644
--- a/src/data/Runnable.vala
+++ b/src/data/Runnable.vala
@@ -341,10 +341,10 @@ namespace GameHub.Data
public abstract class Installer
{
- public string id { get; protected set; }
- public Platform platform { get; protected set; default = Platform.CURRENT; }
- public int64 full_size { get; protected set; default = 0; }
- public string? version { get; protected set; }
+ public string id { get; protected set; }
+ public Platform platform { get; protected set; default = Platform.CURRENT; }
+ public virtual int64 full_size { get; protected set; default = 0; }
+ public string? version { get; protected set; }
public virtual string name { owned get { return id; } }
diff --git a/src/data/db/tables/Games.vala b/src/data/db/tables/Games.vala
index c7fcbda5..9423f20d 100644
--- a/src/data/db/tables/Games.vala
+++ b/src/data/db/tables/Games.vala
@@ -22,6 +22,7 @@ using Sqlite;
using GameHub.Utils;
using GameHub.Data.Sources.Steam;
+using GameHub.Data.Sources.EpicGames;
using GameHub.Data.Sources.GOG;
using GameHub.Data.Sources.Humble;
using GameHub.Data.Sources.Itch;
@@ -311,6 +312,10 @@ namespace GameHub.Data.DB.Tables
{
g = new SteamGame.from_db((Steam) s, st);
}
+ else if(s is EpicGames)
+ {
+ g = new EpicGamesGame.from_db((EpicGames) s, st);
+ }
else if(s is GOG)
{
g = new GOGGame.from_db((GOG) s, st);
@@ -396,6 +401,10 @@ namespace GameHub.Data.DB.Tables
{
g = new SteamGame.from_db((Steam) s, st);
}
+ else if(s is EpicGames)
+ {
+ g = new EpicGamesGame.from_db((EpicGames) s, st);
+ }
else if(s is GOG)
{
g = new GOGGame.from_db((GOG) s, st);
diff --git a/src/data/db/tables/IGDBData.vala b/src/data/db/tables/IGDBData.vala
index 6c151437..bc53146e 100644
--- a/src/data/db/tables/IGDBData.vala
+++ b/src/data/db/tables/IGDBData.vala
@@ -24,6 +24,7 @@ using GameHub.Utils;
using GameHub.Data.Sources.Steam;
using GameHub.Data.Sources.GOG;
using GameHub.Data.Sources.Humble;
+using GameHub.Data.Sources.EpicGames;
namespace GameHub.Data.DB.Tables
{
diff --git a/src/data/db/tables/Tags.vala b/src/data/db/tables/Tags.vala
index dfcad4a0..5803e420 100644
--- a/src/data/db/tables/Tags.vala
+++ b/src/data/db/tables/Tags.vala
@@ -22,6 +22,7 @@ using Sqlite;
using GameHub.Utils;
using GameHub.Data.Sources.Steam;
+using GameHub.Data.Sources.EpicGames;
using GameHub.Data.Sources.GOG;
using GameHub.Data.Sources.Humble;
diff --git a/src/data/sources/epicgames/EpicGames.vala b/src/data/sources/epicgames/EpicGames.vala
new file mode 100644
index 00000000..a011b1a1
--- /dev/null
+++ b/src/data/sources/epicgames/EpicGames.vala
@@ -0,0 +1,199 @@
+/*
+This file is part of GameHub.
+Copyright (C) 2018-2019 Anatoliy Kashkin
+Copyright (C) 2020 Adam Jordanek
+
+GameHub is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GameHub is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GameHub. If not, see .
+*/
+
+using Gee;
+using GameHub.Data.DB;
+using GameHub.Utils;
+
+namespace GameHub.Data.Sources.EpicGames
+{
+ public class EpicGames: GameSource
+ {
+ public static EpicGames instance;
+
+ private bool? installed = null;
+ public File? legendary_executable = null;
+
+ public override string id { get { return "epicgames"; } }
+ public override string name { get { return "EpicGames"; } }
+ public override string icon { get { return "source-epicgames-symbolic"; } }
+
+ private Settings.Auth.EpicGames settings;
+ private FSUtils.Paths.Settings paths = FSUtils.Paths.Settings.instance;
+
+ public override bool enabled
+ {
+ get { return settings.enabled; }
+ set { settings.enabled = value; }
+ }
+
+
+ public LegendaryWrapper? legendary_wrapper { get; private set; }
+
+ public string? user_id { get; protected set; }
+ public string? user_name { get; protected set; }
+
+ public EpicGames()
+ {
+ instance = this;
+ legendary_wrapper = new LegendaryWrapper();
+ settings = Settings.Auth.EpicGames.instance;
+ }
+
+ public override bool is_installed(bool refresh)
+ {
+ /*
+ Epic games depends on
+ */
+ if(installed != null && !refresh)
+ {
+ return (!) installed;
+ }
+
+ //check if legendary exists
+ var legendary = Utils.find_executable(paths.legendary_command);
+
+ if(legendary == null || !legendary.query_exists())
+ {
+ debug("[EpicGames] is_installed: Legendary not found");
+
+ }
+ else
+ {
+ debug("[EpicGames] is_installed: LegendaryYES");
+ }
+
+ legendary_executable = legendary;
+ installed = legendary_executable != null && legendary_executable.query_exists();
+
+ return (!) installed;
+ }
+
+ public override async bool install()
+ {
+ return true;
+ }
+
+ public override async bool authenticate()
+ {
+ debug("[EpicGames] Performing auth");
+ var username = yield legendary_wrapper.auth();
+ settings.authenticated = username != null;
+ if(username != null) {
+ user_name = username;
+ return true;
+ }else return false;
+ }
+
+ public override bool is_authenticated()
+ {
+ var result = legendary_wrapper.is_authenticated();
+ settings.authenticated = result;
+
+ if (result) {
+ legendary_wrapper.get_username.begin ((obj, res) => {
+ user_name = legendary_wrapper.get_username.end (res);
+ });
+ }
+
+ return result;
+ }
+
+ public override bool can_authenticate_automatically()
+ {
+ debug("[EpicGames] can_authenticate_automatically: NOT IMPLEMENTED");
+ return false;
+ }
+
+ private ArrayList _games = new ArrayList(Game.is_equal);
+
+ public override ArrayList games { get { return _games; } }
+
+ public override async ArrayList load_games(Utils.FutureResult2? game_loaded=null, Utils.Future? cache_loaded=null)
+ {
+ if(_games.size > 0)
+ {
+ return _games;
+ }
+
+ debug("[EpicGames] Load games");
+
+ Utils.thread("EpicGamesLoading", () => {
+ _games.clear();
+
+ games_count = 0;
+
+ var cached = Tables.Games.get_all(this);
+ if(cached.size > 0)
+ {
+ foreach(var g in cached)
+ {
+ if(!Settings.UI.Behavior.instance.merge_games || !Tables.Merges.is_game_merged(g))
+ {
+ _games.add(g);
+ if(game_loaded != null)
+ {
+ game_loaded(g, true);
+ }
+ }
+ games_count++;
+ }
+ }
+
+ if(cache_loaded != null)
+ {
+ cache_loaded();
+ }
+
+ var games = legendary_wrapper.getGames();
+ foreach(var game in games)
+ {
+ var g = new EpicGamesGame(this, game.name, game.id);
+ bool is_new_game = !_games.contains(g);
+ if(is_new_game && (!Settings.UI.Behavior.instance.merge_games || !Tables.Merges.is_game_merged(g)))
+ {
+ _games.add(g);
+ if(game_loaded != null)
+ {
+ game_loaded(g, false);
+ }
+ }
+
+ if(is_new_game) {
+ g.save();
+ if(game_loaded != null)
+ {
+ game_loaded(g, true);
+ }
+ _games.add(g);
+ games_count++;
+ } else {
+ var index = _games.index_of(g);
+ _games.get(index).update_status();
+ }
+ }
+ Idle.add(load_games.callback);
+ });
+ yield;
+ return _games;
+ }
+
+
+ }
+}
diff --git a/src/data/sources/epicgames/EpicGamesGame.vala b/src/data/sources/epicgames/EpicGamesGame.vala
new file mode 100644
index 00000000..7aaac468
--- /dev/null
+++ b/src/data/sources/epicgames/EpicGamesGame.vala
@@ -0,0 +1,219 @@
+/*
+This file is part of GameHub.
+Copyright (C) 2018-2019 Anatoliy Kashkin
+Copyright (C) 2020 Adam Jordanek
+
+GameHub is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GameHub is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GameHub. If not, see .
+*/
+using Gtk;
+
+using Gee;
+using GameHub.Data.DB;
+using GameHub.Utils;
+
+using GameHub.Utils.Downloader;
+
+namespace GameHub.Data.Sources.EpicGames
+{
+ public class EpicGamesGame: Game
+ {
+ public ArrayList? installers { get; protected set; default = new ArrayList(); }
+
+ public EpicGamesGame(EpicGames src, string nameP, string idP)
+ {
+ source = src;
+ name = nameP;
+ id = idP;
+ icon = "";
+ image = src.legendary_wrapper.get_image(id);
+ platforms.add(Platform.LINUX);
+
+ install_dir = null;
+ executable_path = "$game_dir/start.sh";
+ work_dir_path = "$game_dir";
+ info_detailed = @"{}";
+
+ mount_overlays.begin();
+ update_status();
+ }
+
+ public override void update_status()
+ {
+ var state = Game.State.UNINSTALLED;
+ if (((EpicGames) source).legendary_wrapper.is_installed(id)) {
+ state = Game.State.INSTALLED;
+ debug ("New installed game: \tname = %s\t", name);
+ } else {
+ debug ("New not installed game: \tname = %s\t", name);
+ }
+
+ if(state == Game.State.INSTALLED)
+ {
+ remove_tag(Tables.Tags.BUILTIN_UNINSTALLED);
+ add_tag(Tables.Tags.BUILTIN_INSTALLED);
+ }
+ else
+ {
+ add_tag(Tables.Tags.BUILTIN_UNINSTALLED);
+ remove_tag(Tables.Tags.BUILTIN_INSTALLED);
+ }
+ status = new Game.Status(state, this);
+ }
+
+ public EpicGamesGame.from_db(EpicGames src, Sqlite.Statement s)
+ {
+ source = src;
+ id = Tables.Games.ID.get(s);
+ name = Tables.Games.NAME.get(s);
+ info = Tables.Games.INFO.get(s);
+ info_detailed = Tables.Games.INFO_DETAILED.get(s);
+ icon = Tables.Games.ICON.get(s);
+ image = src.legendary_wrapper.get_image(id);//Tables.Games.IMAGE.get(s);
+ install_dir = Tables.Games.INSTALL_PATH.get(s) != null ? FSUtils.file(Tables.Games.INSTALL_PATH.get(s)) : null;
+ executable_path = Tables.Games.EXECUTABLE.get(s);
+ work_dir_path = Tables.Games.WORK_DIR.get(s);
+ compat_tool = Tables.Games.COMPAT_TOOL.get(s);
+ compat_tool_settings = Tables.Games.COMPAT_TOOL_SETTINGS.get(s);
+ arguments = Tables.Games.ARGUMENTS.get(s);
+ last_launch = Tables.Games.LAST_LAUNCH.get_int64(s);
+ playtime_source = Tables.Games.PLAYTIME_SOURCE.get_int64(s);
+ playtime_tracked = Tables.Games.PLAYTIME_TRACKED.get_int64(s);
+ image_vertical = Tables.Games.IMAGE_VERTICAL.get(s);
+
+ platforms.clear();
+ var pls = Tables.Games.PLATFORMS.get(s).split(",");
+ foreach(var pl in pls)
+ {
+ foreach(var p in Platform.PLATFORMS)
+ {
+ if(pl == p.id())
+ {
+ platforms.add(p);
+ break;
+ }
+ }
+ }
+ installers.add(new EpicGamesGame.EpicGamesInstaller(this, id));
+ update_status();
+ }
+
+ public override async void install(Runnable.Installer.InstallMode install_mode=Runnable.Installer.InstallMode.INTERACTIVE)
+ {
+ new GameHub.UI.Dialogs.InstallDialog(this, installers, install_mode, install.callback);
+ yield;
+ update_status();
+ }
+ public override async void uninstall()
+ {
+ ((EpicGames) source).legendary_wrapper.uninstall(id);
+ update_status();
+ }
+
+ public override async void run()
+ {
+ ((EpicGames) source).legendary_wrapper.run(id);
+
+ }
+
+ public override void import(bool update=true)
+ {
+ var chooser = new FileChooserDialog(_("Select directory"), GameHub.UI.Windows.MainWindow.instance, FileChooserAction.SELECT_FOLDER);
+
+ chooser.add_button(_("Cancel"), ResponseType.CANCEL);
+ var select_btn = chooser.add_button(_("Select"), ResponseType.ACCEPT);
+
+ select_btn.get_style_context().add_class(Gtk.STYLE_CLASS_SUGGESTED_ACTION);
+ select_btn.grab_default();
+
+ if(chooser.run() == ResponseType.ACCEPT)
+ {
+ install_dir = chooser.get_file();
+ ((EpicGames) source).legendary_wrapper.import_game(id, install_dir.get_path());
+
+ if(update) {
+ update_status();
+ save();
+ }
+ }
+
+ chooser.destroy();
+ }
+
+ public class EpicGamesInstaller: Runnable.Installer
+ {
+ private FSUtils.Paths.Settings paths = FSUtils.Paths.Settings.instance;
+ public EpicGamesGame game;
+ private EpicGames epic;
+ public override string name { owned get { return game.name; } }
+
+ private int64 _full_size = 0;
+ public override int64 full_size {
+ get {
+ if(_full_size != 0) return _full_size;
+ else {
+ var size = epic.legendary_wrapper.get_install_size (game.id);
+ _full_size = size;
+ return _full_size;
+ }
+
+ }
+ set {}
+ }
+
+ public EpicGamesInstaller(EpicGamesGame game, string id)
+ {
+ this.game = game;
+ id = id;
+ platform = Platform.CURRENT;
+ epic = (EpicGames)(game.source);
+ }
+
+ public override async void install(Runnable runnable, CompatTool? tool=null)
+ {
+
+ EpicGamesGame? game = null;
+ if(runnable is EpicGamesGame)
+ {
+ game = runnable as EpicGamesGame;
+ }
+
+ Utils.thread("EpicGamesGame.Installer", () => {
+
+ EpicDownload ed = new EpicDownload(game.id);
+ game.status = new Game.Status(Game.State.DOWNLOADING, game, ed);
+
+ ed.cancelled.connect(() => {
+ epic.legendary_wrapper.cancel_installation();
+ });
+
+ var game_folder = (paths.epic_games == null || paths.epic_games == "") ? null : paths.epic_games;
+ epic.legendary_wrapper.install(game.id, game_folder, progress => {
+ ed.status = new EpicDownload.EpicStatus(progress / 100);
+ game.status = new Game.Status(Game.State.DOWNLOADING, game, ed);
+ });
+
+ Idle.add(install.callback);
+ });
+ yield;
+
+ if(game != null) game.status = new Game.Status(Game.State.INSTALLED, game, null);
+ game.update_status();
+ }
+ }
+ }
+
+
+
+
+}
diff --git a/src/data/sources/epicgames/LegendaryWrapper.vala b/src/data/sources/epicgames/LegendaryWrapper.vala
new file mode 100644
index 00000000..418f24be
--- /dev/null
+++ b/src/data/sources/epicgames/LegendaryWrapper.vala
@@ -0,0 +1,245 @@
+using Gee;
+using GameHub.Utils;
+
+namespace GameHub.Data.Sources.EpicGames
+{
+ public struct LegendaryGame {
+ string name;
+ string id;
+ string version;
+ }
+
+ public class LegendaryWrapper
+ {
+ private Regex regex = /\s?\*\s?(.+)\(App\sname:\s([a-zA-Z0-9]+)\s.\s[Vv]ersion:\s([^)]*)\)/;
+ private Regex authValidationRegex = /credentials are still valid/;
+ private Regex authSuccessRegex = /Successfully logged in as "([^"]+)/;
+ private Regex sidExtractionRegex = /sid":"([^"]+)/;
+ private Regex fileUserRegex = /displayName":\s"([^"]+)/;
+ private Regex progressRegex = /Progress:\s([0-9\.]+)/;
+ private Regex installSizeRegex = /Install size:\s([0-9\.]+)/;
+
+ private FSUtils.Paths.Settings paths = FSUtils.Paths.Settings.instance;
+ private Settings.Auth.EpicGames settings = Settings.Auth.EpicGames.instance;
+
+ private Subprocess? downloadProcess = null;
+
+ public LegendaryWrapper()
+ {
+ }
+
+ public ArrayList getGames() {
+ var result = new ArrayList();
+
+ string? line = null;
+ MatchInfo info;
+ var output = new DataInputStream(new Subprocess.newv ({paths.legendary_command, "list-games"}, STDOUT_PIPE).get_stdout_pipe ());
+
+ while ((line = output.read_line()) != null) {
+ if (regex.match (line, 0, out info)) {
+ LegendaryGame? g = {info.fetch (1), info.fetch (2), info.fetch (3)};
+ result.add(g);
+ }
+ }
+ return result;
+ }
+
+ public string get_image(string id)
+ {
+ string res = "";
+ var file = File.new_for_path(Environment.get_home_dir () + "/.config/legendary/metadata/"+id+".json");
+
+ if (file.query_exists ()) {
+ var dis = new DataInputStream (file.read ());
+ string line;
+
+ while ((line = dis.read_line (null)) != null) {
+ res += line;
+ }
+ var parser = new Json.Parser ();
+ parser.load_from_data (res);
+ var root_object = parser.get_root().get_object();
+
+ var metadata = root_object.get_object_member ("metadata");
+ var keyImages = metadata.get_array_member ("keyImages");
+ var img = keyImages.get_object_element (0).get_string_member ("url");
+ return img;
+ }
+ return "";
+ }
+
+ public void cancel_installation() {
+ if(downloadProcess != null) {
+ downloadProcess.send_signal (2);
+ }
+ }
+
+ public int64 get_install_size(string id) {
+ var process = new Subprocess.newv (
+ {paths.legendary_command, "download", id}, STDOUT_PIPE | STDERR_PIPE);
+ var output = new DataInputStream(process.get_stdout_pipe ());
+ var errOutput = new DataInputStream(process.get_stderr_pipe ());
+
+ string line;
+ MatchInfo info;
+ while ((line = errOutput.read_line ()) != null) {
+ if(installSizeRegex.match (line, 0, out info)) {
+ int64 size = ((int64) double.parse (info.fetch (1))) * 1000000;
+ process.send_signal (2);
+ return size;
+ }
+ }
+
+ process.send_signal (2);
+ return 0;
+ }
+
+ public void install(string id, string? game_folder = null, Utils.FutureResult? progress=null)
+ {
+ string[] command = {paths.legendary_command, "install", id};
+ if (game_folder != null) {
+ command = {paths.legendary_command, "install", id, "--base-path", game_folder};
+ }
+
+ downloadProcess = new Subprocess.newv (command, STDOUT_PIPE | STDIN_PIPE | STDERR_PIPE);
+
+ var input = new DataOutputStream(downloadProcess.get_stdin_pipe ());
+ var output = new DataInputStream(downloadProcess.get_stdout_pipe ());
+ var outputError = new DataInputStream(downloadProcess.get_stderr_pipe ());
+
+ string? line = null;
+ input.put_string("y\n");
+
+ MatchInfo info;
+ while ((line = outputError.read_line()) != null) {
+ if(progressRegex.match (line, 0, out info)) {
+ progress(double.parse (info.fetch(1)));
+ }
+ }
+
+ refresh_installed = true;
+ }
+
+ public bool is_authenticated() {
+ var savedSid = settings.sid;
+ if (savedSid == "") savedSid = "test";
+
+ string? output = null;
+ string? error = null;
+ new Subprocess.newv ({paths.legendary_command, "auth", "--sid", savedSid}, STDOUT_PIPE | STDERR_PIPE).communicate_utf8(null, null, out output, out error);
+
+ if (output.contains("ERROR")) return false;
+ else if(output.contains("Stored credentials are still valid")) return true;
+ else if (error.contains("ERROR")) return false;
+ else if(error.contains("Stored credentials are still valid")) return true;
+
+ return false;
+ }
+
+ public async string? get_username() {
+ File userfile = File.new_for_path(GLib.Environment.get_home_dir () + "/.config/legendary/user.json");
+ if (userfile.query_exists ()) {
+ var dis = new DataInputStream (userfile.read ());
+ string line;
+
+ MatchInfo match;
+ while ((line = dis.read_line (null)) != null)
+ if(fileUserRegex.match (line, 0, out match)) return match.fetch (1);
+
+ return null;
+ }else return null;
+ }
+
+ public async string? auth()
+ {
+ if(is_authenticated()) {
+ var username = yield get_username();
+ if (username != null) return username;
+ }
+
+ //Do auth process
+ string url = "https://www.epicgames.com/id/login?redirectUrl=https://www.epicgames.com/id/api/redirect";
+ var wnd = new GameHub.UI.Windows.WebAuthWindow(EpicGames.instance.name, url, "https://www.epicgames.com/id/api/redirect");
+
+ string? username = null;
+ wnd.pageLoaded.connect(page => {
+ MatchInfo info;
+ sidExtractionRegex.match(page, 0, out info);
+ var sid = info.fetch(1);
+
+ //Legendary auth with sid
+ var output = new DataInputStream(new Subprocess.newv ({paths.legendary_command, "auth", "--sid", sid}, STDOUT_PIPE).get_stdout_pipe ());
+ string? line = null;
+ while ((line = output.read_line()) != null) {
+ if(authSuccessRegex.match(line, 0, out info)) {
+ username = info.fetch(1);
+ settings.sid = sid;
+ debug("[EpicGames] Successfully logged in as %s", username);
+
+ Idle.add(auth.callback);
+ break;
+ }
+ }
+ });
+
+ wnd.canceled.connect(() => Idle.add(auth.callback));
+
+ wnd.set_size_request(550, 680);
+ wnd.show_all();
+ wnd.present();
+
+ yield;
+ return username;
+ }
+
+ public void uninstall(string id)
+ {
+ // FIXME: It can be done much better
+ var process = new Subprocess.newv ({paths.legendary_command, "uninstall", id}, STDOUT_PIPE | STDIN_PIPE);
+ var input = new DataOutputStream(process.get_stdin_pipe ());
+ var output = new DataInputStream(process.get_stdout_pipe ());
+ string? line = null;
+ input.put_string("y\n");
+ while ((line = output.read_line()) != null) {
+ debug("[EpicGames] %s", line);
+ }
+ refresh_installed = true;
+ }
+
+ public void import_game(string id, string path) {
+ var process = new Subprocess.newv ({paths.legendary_command, "import-game", id, path}, STDOUT_PIPE);
+ }
+
+ public void run(string id) {
+ // FIXME: not good idea
+ new Subprocess.newv ({paths.legendary_command, "launch", id}, STDOUT_PIPE);
+ }
+
+ private bool refresh_installed = true;
+ private ArrayList _installed = new ArrayList();
+
+ public bool is_installed(string id)
+ {
+ if(refresh_installed) {
+ build_installed_list();
+ refresh_installed = false;
+ }
+ return _installed.contains(id);
+ }
+
+
+ private void build_installed_list()
+ {
+ var installed_output = new DataInputStream(new Subprocess.newv ({paths.legendary_command, "list-installed"}, STDOUT_PIPE).get_stdout_pipe ());
+ _installed.clear();
+ string? line = null;
+ MatchInfo info;
+ while ((line = installed_output.read_line()) != null) {
+ if (regex.match (line, 0, out info)) {
+ _installed.add(info.fetch(2));
+ }
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/meson.build b/src/meson.build
index 2acdeac9..e53e0f8b 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -45,6 +45,10 @@ sources = [
'data/sources/steam/Steam.vala',
'data/sources/steam/SteamGame.vala',
+ 'data/sources/epicgames/EpicGames.vala',
+ 'data/sources/epicgames/EpicGamesGame.vala',
+ 'data/sources/epicgames/LegendaryWrapper.vala',
+
'data/sources/gog/GOG.vala',
'data/sources/gog/GOGGame.vala',
@@ -104,6 +108,7 @@ sources = [
'ui/dialogs/SettingsDialog/pages/general/Collection.vala',
'ui/dialogs/SettingsDialog/pages/general/Tweaks.vala',
'ui/dialogs/SettingsDialog/pages/sources/Steam.vala',
+ 'ui/dialogs/SettingsDialog/pages/sources/EpicGames.vala',
'ui/dialogs/SettingsDialog/pages/sources/GOG.vala',
'ui/dialogs/SettingsDialog/pages/sources/Humble.vala',
'ui/dialogs/SettingsDialog/pages/sources/Itch.vala',
@@ -186,7 +191,8 @@ sources = [
'settings/Tweaks.vala',
'utils/downloader/Downloader.vala',
- 'utils/downloader/SoupDownloader.vala'
+ 'utils/downloader/SoupDownloader.vala',
+ 'utils/downloader/EpicDownloader.vala'
]
if get_option('os') == 'linux'
diff --git a/src/settings/Auth.vala b/src/settings/Auth.vala
index fa0b91cf..3d2c7b76 100644
--- a/src/settings/Auth.vala
+++ b/src/settings/Auth.vala
@@ -56,6 +56,31 @@ namespace GameHub.Settings.Auth
}
}
+ public class EpicGames: SettingsSchema
+ {
+ public bool enabled { get; set; }
+ public bool authenticated { get; set; }
+ public string sid { get; set; }
+
+ public EpicGames()
+ {
+ base(ProjectConfig.PROJECT_NAME + ".auth.epicgames");
+ }
+
+ private static EpicGames? _instance;
+ public static unowned EpicGames instance
+ {
+ get
+ {
+ if(_instance == null)
+ {
+ _instance = new EpicGames();
+ }
+ return _instance;
+ }
+ }
+ }
+
public class GOG: SettingsSchema
{
public bool enabled { get; set; }
diff --git a/src/ui/dialogs/InstallDialog.vala b/src/ui/dialogs/InstallDialog.vala
index 03cc0f7a..f2835417 100644
--- a/src/ui/dialogs/InstallDialog.vala
+++ b/src/ui/dialogs/InstallDialog.vala
@@ -213,7 +213,11 @@ namespace GameHub.UI.Dialogs
}
else
{
- subtitle_label.label = _("Installer size: %s").printf(fsize(installers[0].full_size));
+ subtitle_label.label = _("Installer size: calculating...");
+ Utils.thread("CalculatingFileSize", () => {
+ subtitle_label.label = _("Installer size: %s").printf(fsize(installers[0].full_size));
+ });
+
}
Revealer? compat_tool_revealer = new Revealer();
@@ -374,7 +378,11 @@ namespace GameHub.UI.Dialogs
name.hexpand = true;
name.halign = Align.START;
- var size = new Label(fsize(installer.full_size));
+ var size = new Label("calculating...");
+ Utils.thread("CalculatingFileSize", () => {
+ size.label = fsize(installer.full_size);
+ });
+
size.halign = Align.END;
box.add(icon);
diff --git a/src/ui/dialogs/SettingsDialog/SettingsDialog.vala b/src/ui/dialogs/SettingsDialog/SettingsDialog.vala
index 2c15973f..b71cf692 100644
--- a/src/ui/dialogs/SettingsDialog/SettingsDialog.vala
+++ b/src/ui/dialogs/SettingsDialog/SettingsDialog.vala
@@ -89,6 +89,7 @@ namespace GameHub.UI.Dialogs.SettingsDialog
#endif
add_page("sources/steam", new Pages.Sources.Steam(this));
+ add_page("sources/epicgames", new Pages.Sources.EpicGames(this));
add_page("sources/gog", new Pages.Sources.GOG(this));
add_page("sources/humble", new Pages.Sources.Humble(this));
add_page("sources/itch", new Pages.Sources.Itch(this));
diff --git a/src/ui/dialogs/SettingsDialog/pages/sources/EpicGames.vala b/src/ui/dialogs/SettingsDialog/pages/sources/EpicGames.vala
new file mode 100644
index 00000000..980baf5f
--- /dev/null
+++ b/src/ui/dialogs/SettingsDialog/pages/sources/EpicGames.vala
@@ -0,0 +1,104 @@
+/*
+This file is part of GameHub.
+Copyright (C) 2018-2019 Anatoliy Kashkin
+
+GameHub is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GameHub is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GameHub. If not, see .
+*/
+
+using Gtk;
+
+using GameHub.Utils;
+using GameHub.UI.Widgets;
+using GameHub.Data.Sources.EpicGames;
+
+namespace GameHub.UI.Dialogs.SettingsDialog.Pages.Sources
+{
+ public class EpicGames: SettingsDialogPage
+ {
+
+ private LegendaryWrapper? legendary_wrapper { get; private set; }
+ private Settings.Auth.EpicGames epicgames_auth;
+ private GameHub.Data.Sources.EpicGames.EpicGames epic = GameHub.Data.Sources.EpicGames.EpicGames.instance;
+
+ private Button logout_btn;
+
+ public EpicGames(SettingsDialog dlg)
+ {
+ Object(
+ dialog: dlg,
+ title: "EpicGames",
+ description: _("Disabled"),
+ icon_name: "source-epicgames-symbolic",
+ activatable: true
+ );
+ status = description;
+ }
+
+ construct
+ {
+ var paths = FSUtils.Paths.Settings.instance;
+ epicgames_auth = Settings.Auth.EpicGames.instance;
+
+ status_switch.active = epicgames_auth.enabled;
+ status_switch.notify["active"].connect(() => {
+ epicgames_auth.enabled = status_switch.active;
+ request_restart();
+ update();
+ });
+
+ logout_btn = new Button.with_label(_("Logout"));
+ action_area.add(logout_btn);
+
+ logout_btn.clicked.connect(() => {
+ epicgames_auth.authenticated = false;
+ epicgames_auth.sid = "";
+ request_restart();
+ update();
+ });
+
+ add_entry("Legendary client command", paths.legendary_command, (command) => {
+ paths.legendary_command = command;
+ });
+
+ var game_default_folder = (paths.epic_games == null || paths.epic_games == "") ? _("Default") : paths.epic_games;
+ add_file_chooser(_("Games directory"), FileChooserAction.SELECT_FOLDER, game_default_folder, v => { paths.epic_games = v; request_restart(); }, false);
+ update();
+ }
+
+ private void update()
+ {
+ content_area.sensitive = epicgames_auth.enabled;
+ logout_btn.sensitive = epicgames_auth.authenticated;
+
+ if(!epicgames_auth.enabled)
+ {
+ status = description = _("Disabled");
+ }
+ else if(!epic.is_installed())
+ {
+ status = description = _("Missing Legendary");
+ }
+ else if(!epicgames_auth.authenticated)
+ {
+ status = description = _("Not authenticated");
+ }
+ else
+ {
+ var user_name = GameHub.Data.Sources.EpicGames.EpicGames.instance.user_name;
+ status = description = user_name != null ? _("Authenticated as %s").printf(user_name) : _("Authenticated");
+ }
+ }
+
+ }
+}
diff --git a/src/ui/views/WelcomeView.vala b/src/ui/views/WelcomeView.vala
index 1029a4ab..e1271bb6 100644
--- a/src/ui/views/WelcomeView.vala
+++ b/src/ui/views/WelcomeView.vala
@@ -96,6 +96,7 @@ namespace GameHub.UI.Views
foreach(var src in GameSources)
{
+ debug("[GS] %s", src.icon);
welcome.append(src.icon, src.name, "");
}
@@ -126,12 +127,11 @@ namespace GameHub.UI.Views
var src = GameSources[index];
var btn = welcome.get_button_from_index(index);
-
welcome.set_item_visible(index, !(src is Sources.Humble.Trove) && !(src is Sources.User.User) && src.enabled);
if(src is Sources.Humble.Trove || !src.enabled) continue;
enabled_sources++;
-
+ debug("[GS] %s %s", src.name, src.is_installed(true).to_string());
if(src.is_installed(true))
{
btn.title = src.name;
diff --git a/src/ui/windows/WebAuthWindow.vala b/src/ui/windows/WebAuthWindow.vala
index 9eec4673..1d024ee5 100644
--- a/src/ui/windows/WebAuthWindow.vala
+++ b/src/ui/windows/WebAuthWindow.vala
@@ -36,6 +36,7 @@ namespace GameHub.UI.Windows
private bool is_finished = false;
public signal void finished(string url);
+ public signal void pageLoaded(string page);
public signal void canceled();
private const string GOG_CSS = "body { background-color: #d2d2d2 !important; } ._modal__box { box-shadow: none !important; vertical-align: top !important; margin-top: 0 !important; } ._modal__control, .form__buttons-container, .form__separator { display: none !important; }";
@@ -129,16 +130,30 @@ namespace GameHub.UI.Windows
debug("[WebAuth/%s] Finished with result `%s`", source, token);
}
finished(token);
- destroy();
+
+ //Execute javascript to extract page source
+ runJavascript.begin ("document.body.childNodes[0].textContent", (obj, res) => {
+ pageLoaded(runJavascript.end (res).get_js_value().to_string());
+ destroy();
+ });
}
+
+
});
webview.load_uri(url);
add(webview);
+
#endif
destroy.connect(() => { if(!is_finished) canceled(); });
}
+
+ private async WebKit.JavascriptResult runJavascript(string script) {
+ return yield webview.run_javascript(script);
+ }
+
+
}
}
diff --git a/src/utils/FSUtils.vala b/src/utils/FSUtils.vala
index c90b72da..86057b6f 100644
--- a/src/utils/FSUtils.vala
+++ b/src/utils/FSUtils.vala
@@ -41,6 +41,8 @@ namespace GameHub.Utils
public string humble_games { get; set; }
public string itch_home { get; set; }
public string itch_games { get; set; }
+ public string legendary_command { get; set; }
+ public string epic_games { get; set; }
public Settings()
{
diff --git a/src/utils/downloader/EpicDownloader.vala b/src/utils/downloader/EpicDownloader.vala
new file mode 100644
index 00000000..a23a380b
--- /dev/null
+++ b/src/utils/downloader/EpicDownloader.vala
@@ -0,0 +1,49 @@
+/*
+This file is part of GameHub.
+Copyright (C) 2018-2019 Anatoliy Kashkin
+Copyright (C) 2020 Adam Jordanek
+
+GameHub is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GameHub is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GameHub. If not, see .
+*/
+
+using GLib;
+using Gee;
+
+namespace GameHub.Utils.Downloader
+{
+
+ public class EpicDownload : Download {
+
+ public EpicDownload(string id)
+ {
+ base(id);
+ }
+
+ public signal void cancelled();
+ public override void cancel() {
+ cancelled();
+ }
+
+ public class EpicStatus : Download.Status {
+ private double _progress = -1;
+ public override double progress { get { return _progress; } }
+
+ public EpicStatus(double progress) {
+ this._progress = progress;
+ }
+
+ }
+ }
+
+}
\ No newline at end of file