Florian RICHER
efb95c2bb2
Add dot_config/spicetify/CustomApps/spicetify-marketplace/CONTRIBUTING.md Add dot_config/spicetify/CustomApps/spicetify-marketplace/LICENSE Add dot_config/spicetify/CustomApps/spicetify-marketplace/README.md Add dot_config/spicetify/CustomApps/spicetify-marketplace/blacklist.json Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_eslintrc.json Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_github/ISSUE_TEMPLATE/bug_report.yml Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_github/ISSUE_TEMPLATE/config.yml Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_github/ISSUE_TEMPLATE/feature_request.yml Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_github/ISSUE_TEMPLATE/malicious_extension_report.yml Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_github/dependabot.yml Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_github/workflows/lint.yml Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_gitignore Add dot_config/spicetify/CustomApps/spicetify-marketplace/dot_nvmrc Add dot_config/spicetify/CustomApps/spicetify-marketplace/executable_install.sh Add dot_config/spicetify/CustomApps/spicetify-marketplace/extension.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/index.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/install.ps1 Add dot_config/spicetify/CustomApps/spicetify-marketplace/manifest.json Add dot_config/spicetify/CustomApps/spicetify-marketplace/package-lock.json Add dot_config/spicetify/CustomApps/spicetify-marketplace/package.json Add dot_config/spicetify/CustomApps/spicetify-marketplace/snippets.json Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/AddSnippetModal.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/Card.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/Icons.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/OptionsMenu.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/ReadmePage.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/ReloadModal.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/Settings.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/SortBox.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/TabBar.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/src/Utils.js Add dot_config/spicetify/CustomApps/spicetify-marketplace/style.css Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/add-snippet-modal.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/card.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/fixes.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/grid.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/readme-pages.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/reload-modal.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/components/settings.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/styles/style.scss Add dot_config/spicetify/CustomApps/spicetify-marketplace/tsconfig.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_executable_index.html Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_executable_login.css Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_executable_login.js Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_executable_manifest.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_executable_vendor~login.css Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_executable_vendor~login.js Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIAraOnly-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIAraOnly-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIAraOnly-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIAraOnly-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUICyrOnly-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUICyrOnly-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUICyrOnly-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUICyrOnly-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIHbrOnly-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIHbrOnly-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIHbrOnly-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIHbrOnly-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIv3T-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIv3T-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIv3T-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_CircularSpUIv3T-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_fonts/private_executable_spoticon_regular_2.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable___longest.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_af.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_am.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ar.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_az.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_bg.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_bho.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_bn.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_cs.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_da.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_de.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_el.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_en.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_es-419.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_es.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_et.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_fa.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_fi.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_fil.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_fr-CA.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_fr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_gu.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_he.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_hi.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_hr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_hu.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_id.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_is.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_it.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ja.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_kn.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ko.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_lt.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_lv.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ml.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_mr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ms.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_nb.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ne.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_nl.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_or.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_pa-IN.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_pa-PK.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_pl.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_pt-BR.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_pt-PT.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ro.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ru.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_sk.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_sl.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_sr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_sv.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_sw.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ta.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_te.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_th.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_tr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_uk.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_ur.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_vi.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_zh-CN.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_zh-TW.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_i18n/private_executable_zu.json Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_executable_background.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_executable_eye.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_executable_logo.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_executable_scrollbar-buttons.png Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_content-rtl.avif Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_content-small-rtl.avif Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_content-small.avif Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_content.avif Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_controls.png Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_footer-left.png Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_footer-right.png Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_fake-web-player/private_executable_side.png Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_social-buttons/private_executable_apple.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_social-buttons/private_executable_facebook.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_login/private_images/private_social-buttons/private_executable_google.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_12.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_185.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_188.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_188.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_258.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_258.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_375.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_375.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_381.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_396.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_448.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_479.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_479.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_696.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_774.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_774.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_818.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_818.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_blank.html Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_collection-music-download.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_in-app-messaging-preview.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_in-app-messaging-preview.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_index.html Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_licenses.html Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_manifest.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_vendor~xpui.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_vendor~xpui.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-desktop-modals.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-desktop-modals.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-desktop-routes-debug-utils.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-desktop-routes-debug-utils.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-desktop-routes-homepage-takeover-ad.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-desktop-routes-homepage-takeover-ad.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-album.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-all-episode-sponsors.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-all-episode-sponsors.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-all-show-sponsors.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-artist.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-artist.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-blend.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-blend.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-collection-concerts.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-collection-concerts.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-collection-local-files.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-collection-local-files.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-concert.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-concert.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-create-playlist.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-download-page.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-download-page.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-enhanced-playlist.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-enhanced-playlist.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-episode.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-episode.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-folder.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-folder.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-offline-browse.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-offline-browse.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-playlist.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-playlist.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-profile.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-profile.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-queue.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-queue.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-track-v2.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-track-v2.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-track.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-view.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui-routes-view.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui.css Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_executable_xpui.js Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIAraOnly-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIAraOnly-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIAraOnly-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIAraOnly-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUICyrOnly-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUICyrOnly-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUICyrOnly-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUICyrOnly-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIHbrOnly-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIHbrOnly-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIHbrOnly-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIHbrOnly-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIv3T-Black.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIv3T-Bold.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIv3T-Book.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_fonts/private_executable_CircularSpUIv3T-Light.woff2 Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable___longest.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_af.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_am.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ar.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_az.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_bg.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_bho.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_bn.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_cs.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_da.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_de.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_el.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_en.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_es-419.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_es.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_et.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_fa.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_fi.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_fil.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_fr-CA.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_fr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_gu.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_he.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_hi.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_hr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_hu.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_id.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_is.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_it.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ja.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_kn.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ko.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_lt.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_lv.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ml.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_mr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ms.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_nb.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ne.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_nl.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_or.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_pa-IN.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_pa-PK.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_pl.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_pt-BR.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_pt-PT.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ro.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ru.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_sk.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_sl.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_sr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_sv.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_sw.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ta.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_te.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_th.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_tr.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_uk.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_ur.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_vi.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_zh-CN.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_zh-TW.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_i18n/private_executable_zu.json Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_devices/private_executable_mac.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_connect-to-devices-white.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_connect_header@1x.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_equaliser-animated-green.gif Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_equaliser-green.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_hifi-button-off.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_hifi-button-on.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_hifi.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_playlist-folder-filled.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_station-header-wave.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_station-wave.svg Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_ahsoka1.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_anakin.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_leia.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_luke.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_mace.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_rey.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_sw_saber_vader.png Add dot_config/spicetify/private_Extracted/private_Raw/private_xpui/private_images/private_executable_tracklist-placeholder.png Add dot_config/spicetify/private_Extracted/private_Raw/private_zlink/private_executable_index.html Add dot_config/spicetify/private_Extracted/private_Raw/private_zlink/private_executable_manifest.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_executable_index.html Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_executable_login.css Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_executable_login.js Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_executable_manifest.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_executable_vendor~login.css Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_executable_vendor~login.js Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_fonts/.keep Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable___longest.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_af.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_am.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ar.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_az.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_bg.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_bho.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_bn.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_cs.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_da.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_de.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_el.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_en.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_es-419.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_es.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_et.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_fa.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_fi.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_fil.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_fr-CA.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_fr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_gu.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_he.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_hi.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_hr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_hu.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_id.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_is.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_it.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ja.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_kn.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ko.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_lt.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_lv.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ml.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_mr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ms.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_nb.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ne.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_nl.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_or.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_pa-IN.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_pa-PK.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_pl.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_pt-BR.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_pt-PT.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ro.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ru.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_sk.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_sl.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_sr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_sv.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_sw.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ta.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_te.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_th.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_tr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_uk.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_ur.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_vi.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_zh-CN.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_zh-TW.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_i18n/private_executable_zu.json Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_images/private_fake-web-player/.keep Add dot_config/spicetify/private_Extracted/private_Themed/private_login/private_images/private_social-buttons/.keep Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_12.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_185.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_188.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_188.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_258.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_258.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_375.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_375.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_381.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_396.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_448.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_479.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_479.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_696.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_774.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_774.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_818.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_818.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_blank.html Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_collection-music-download.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_in-app-messaging-preview.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_in-app-messaging-preview.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_index.html Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_licenses.html Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_manifest.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_vendor~xpui.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_vendor~xpui.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-desktop-modals.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-desktop-modals.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-desktop-routes-debug-utils.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-desktop-routes-debug-utils.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-desktop-routes-homepage-takeover-ad.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-desktop-routes-homepage-takeover-ad.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-album.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-all-episode-sponsors.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-all-episode-sponsors.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-all-show-sponsors.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-artist.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-artist.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-blend.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-blend.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-collection-concerts.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-collection-concerts.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-collection-local-files.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-collection-local-files.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-concert.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-concert.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-create-playlist.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-download-page.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-download-page.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-enhanced-playlist.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-enhanced-playlist.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-episode.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-episode.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-folder.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-folder.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-offline-browse.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-offline-browse.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-playlist.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-playlist.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-profile.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-profile.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-queue.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-queue.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-track-v2.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-track-v2.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-track.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-view.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui-routes-view.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui.css Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_executable_xpui.js Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_fonts/.keep Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable___longest.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_af.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_am.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ar.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_az.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_bg.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_bho.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_bn.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_cs.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_da.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_de.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_el.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_en.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_es-419.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_es.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_et.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_fa.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_fi.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_fil.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_fr-CA.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_fr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_gu.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_he.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_hi.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_hr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_hu.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_id.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_is.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_it.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ja.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_kn.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ko.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_lt.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_lv.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ml.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_mr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ms.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_nb.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ne.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_nl.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_or.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_pa-IN.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_pa-PK.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_pl.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_pt-BR.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_pt-PT.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ro.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ru.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_sk.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_sl.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_sr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_sv.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_sw.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ta.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_te.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_th.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_tr.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_uk.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_ur.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_vi.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_zh-CN.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_zh-TW.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_i18n/private_executable_zu.json Add dot_config/spicetify/private_Extracted/private_Themed/private_xpui/private_images/private_devices/.keep Add dot_config/spicetify/private_Extracted/private_Themed/private_zlink/private_executable_index.html Add dot_config/spicetify/private_Extracted/private_Themed/private_zlink/private_executable_manifest.json
838 lines
34 KiB
JavaScript
838 lines
34 KiB
JavaScript
/// <reference types="react" />
|
|
/// <reference types="react-dom" />
|
|
/// <reference path="../spicetify-cli/globals.d.ts" />
|
|
/// <reference path="../spicetify-cli/jsHelper/spicetifyWrapper.js" />
|
|
/// <reference path="src/Card.js" />
|
|
/// <reference path="src/Icons.js" />
|
|
/// <reference path="src/Settings.js" />
|
|
/// <reference path="src/SortBox.js" />
|
|
/// <reference path="src/TabBar.js" />
|
|
/// <reference path="src/ReadmePage.js" />
|
|
/// <reference path="src/Utils.js" />
|
|
|
|
/* eslint-disable no-redeclare, no-unused-vars */
|
|
/** @type {React} */
|
|
const react = Spicetify.React;
|
|
/** @type {import("react-dom")} */
|
|
const reactDOM = Spicetify.ReactDOM;
|
|
const {
|
|
URI,
|
|
React: { useState, useEffect, useCallback },
|
|
// @ts-ignore
|
|
Platform: { History },
|
|
} = Spicetify;
|
|
/* eslint-enable no-redeclare, no-unused-vars */
|
|
|
|
// eslint-disable-next-line no-redeclare
|
|
const LOCALSTORAGE_KEYS = {
|
|
"installedExtensions": "marketplace:installed-extensions",
|
|
"installedSnippets": "marketplace:installed-snippets",
|
|
"installedThemes": "marketplace:installed-themes",
|
|
"activeTab": "marketplace:active-tab",
|
|
"tabs": "marketplace:tabs",
|
|
"sortBy": "marketplace:sort-by",
|
|
// Theme installed store the localsorage key of the theme (e.g. marketplace:installed:NYRI4/Comfy-spicetify/user.css)
|
|
"themeInstalled": "marketplace:theme-installed",
|
|
};
|
|
|
|
// Define a function called "render" to specify app entry point
|
|
// This function will be used to mount app to main view.
|
|
// eslint-disable-next-line no-unused-vars
|
|
function render() {
|
|
const { location } = Spicetify.Platform.History;
|
|
|
|
// If page state set to display readme, render it
|
|
// (This location state data comes from Card.openReadme())
|
|
if (location.pathname === "/spicetify-marketplace/readme") {
|
|
return react.createElement(ReadmePage, {
|
|
title: "Spicetify Marketplace - Readme",
|
|
data: location.state.data,
|
|
});
|
|
} // Otherwise, render the main Grid
|
|
else {
|
|
return react.createElement(Grid, { title: "Spicetify Marketplace" });
|
|
}
|
|
}
|
|
|
|
// Initalize topbar tabs
|
|
// Data initalized in TabBar.js
|
|
// eslint-disable-next-line no-redeclare
|
|
const ALL_TABS = [
|
|
{ name: "Extensions", enabled: true },
|
|
{ name: "Themes", enabled: true },
|
|
{ name: "Snippets", enabled: true },
|
|
{ name: "Installed", enabled: true },
|
|
];
|
|
let tabsString = localStorage.getItem(LOCALSTORAGE_KEYS.tabs);
|
|
let tabs = [];
|
|
try {
|
|
tabs = JSON.parse(tabsString);
|
|
if (!Array.isArray(tabs)) {
|
|
throw new Error("Could not parse marketplace tabs key");
|
|
} else if (tabs.length === 0) {
|
|
throw new Error("Empty marketplace tabs key");
|
|
} else if (tabs.filter(tab => !tab).length > 0) {
|
|
throw new Error("Falsey marketplace tabs key");
|
|
}
|
|
} catch {
|
|
tabs = ALL_TABS;
|
|
localStorage.setItem(LOCALSTORAGE_KEYS.tabs, JSON.stringify(tabs));
|
|
}
|
|
|
|
// Get active theme
|
|
let schemes = [];
|
|
let activeScheme = null;
|
|
try {
|
|
const installedThemeKey = localStorage.getItem(LOCALSTORAGE_KEYS.themeInstalled);
|
|
if (installedThemeKey) {
|
|
const installedThemeDataStr = localStorage.getItem(installedThemeKey);
|
|
if (!installedThemeDataStr) throw new Error("No installed theme data");
|
|
|
|
const installedTheme = JSON.parse(installedThemeDataStr);
|
|
schemes = installedTheme.schemes;
|
|
activeScheme = installedTheme.activeScheme;
|
|
} else {
|
|
console.log("No theme set as installed");
|
|
}
|
|
} catch (err) {
|
|
console.error(err);
|
|
}
|
|
|
|
// eslint-disable-next-line no-redeclare
|
|
const CONFIG = {
|
|
// Fetch the settings and set defaults. Used in Settings.js
|
|
visual: {
|
|
stars: JSON.parse(localStorage.getItem("marketplace:stars")) ?? true,
|
|
tags: JSON.parse(localStorage.getItem("marketplace:tags")) ?? true,
|
|
hideInstalled: JSON.parse(localStorage.getItem("marketplace:hideInstalled")) ?? false,
|
|
colorShift: JSON.parse(localStorage.getItem("marketplace:colorShift")) ?? false,
|
|
// Legacy from reddit app...
|
|
type: JSON.parse(localStorage.getItem("marketplace:type")) ?? false,
|
|
// I was considering adding watchers as "followers" but it looks like the value is a duplicate
|
|
// of stargazers, and the subscribers_count isn't returned in the main API call we make
|
|
// https://github.community/t/bug-watchers-count-is-the-duplicate-of-stargazers-count/140865/4
|
|
followers: JSON.parse(localStorage.getItem("marketplace:followers")) ?? false,
|
|
},
|
|
tabs,
|
|
activeTab: localStorage.getItem(LOCALSTORAGE_KEYS.activeTab),
|
|
theme: {
|
|
activeThemeKey: localStorage.getItem(LOCALSTORAGE_KEYS.themeInstalled) || null,
|
|
schemes,
|
|
activeScheme,
|
|
},
|
|
};
|
|
|
|
if (!CONFIG.activeTab || !CONFIG.tabs.filter(tab => tab.name === CONFIG.activeTab).length) {
|
|
CONFIG.activeTab = CONFIG.tabs[0].name;
|
|
}
|
|
|
|
// Fetches the sorting options, fetched from SortBox.js
|
|
// eslint-disable-next-line no-redeclare
|
|
let sortConfig = {
|
|
by: localStorage.getItem(LOCALSTORAGE_KEYS.sortBy) || "top",
|
|
};
|
|
let cardList = [];
|
|
let endOfList = false;
|
|
let lastScroll = 0;
|
|
let requestQueue = [];
|
|
let requestPage = null;
|
|
// Max GitHub API items per page
|
|
// https://docs.github.com/en/rest/reference/search#search-repositories
|
|
const ITEMS_PER_REQUEST = 100;
|
|
|
|
let BLACKLIST = [];
|
|
|
|
// eslint-disable-next-line no-redeclare, no-unused-vars
|
|
let gridUpdateTabs, gridUpdatePostsVisual;
|
|
|
|
class Grid extends react.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
Object.assign(this, props);
|
|
this.state = {
|
|
cards: [],
|
|
tabs: CONFIG.tabs,
|
|
rest: true,
|
|
endOfList: endOfList,
|
|
schemes: CONFIG.theme.schemes,
|
|
activeScheme: CONFIG.theme.activeScheme,
|
|
activeThemeKey: CONFIG.theme.activeThemeKey,
|
|
};
|
|
}
|
|
|
|
// TODO: should I put this in Grid state?
|
|
getInstalledTheme() {
|
|
const installedThemeKey = localStorage.getItem(LOCALSTORAGE_KEYS.themeInstalled);
|
|
if (!installedThemeKey) return null;
|
|
|
|
const installedThemeDataStr = localStorage.getItem(installedThemeKey);
|
|
if (!installedThemeDataStr) return null;
|
|
|
|
const installedTheme = JSON.parse(installedThemeDataStr);
|
|
return installedTheme;
|
|
}
|
|
|
|
newRequest(amount) {
|
|
cardList = [];
|
|
const queue = [];
|
|
requestQueue.unshift(queue);
|
|
this.loadAmount(queue, amount);
|
|
}
|
|
|
|
/**
|
|
* @param {Object} item
|
|
* @param {"extension" | "theme" | "snippet"} type The type of card
|
|
*/
|
|
appendCard(item, type) {
|
|
item.visual = CONFIG.visual;
|
|
// Set key prop so items don't get stuck when switching tabs
|
|
item.key = `${CONFIG.activeTab}:${item.title}`;
|
|
item.type = type;
|
|
// Pass along the functions to update Grid state on apply
|
|
item.updateColourSchemes = this.updateColourSchemes.bind(this);
|
|
item.updateActiveTheme = this.setActiveTheme.bind(this);
|
|
// This isn't used other than to trigger a re-render
|
|
item.activeThemeKey = this.state.activeThemeKey;
|
|
cardList.push(react.createElement(Card, item));
|
|
this.setState({ cards: cardList });
|
|
}
|
|
|
|
// TODO: this isn't currently used, but it will be used for sorting (based on the SortBox component)
|
|
updateSort(sortByValue) {
|
|
if (sortByValue) {
|
|
sortConfig.by = sortByValue;
|
|
localStorage.setItem(LOCALSTORAGE_KEYS.sortBy, sortByValue);
|
|
}
|
|
|
|
requestPage = null;
|
|
cardList = [];
|
|
this.setState({
|
|
cards: [],
|
|
rest: false,
|
|
endOfList: false,
|
|
});
|
|
endOfList = false;
|
|
|
|
this.newRequest(ITEMS_PER_REQUEST);
|
|
}
|
|
|
|
updateTabs() {
|
|
this.setState({
|
|
tabs: [...CONFIG.tabs],
|
|
});
|
|
}
|
|
|
|
updatePostsVisual() {
|
|
cardList = cardList.map(card => {
|
|
return react.createElement(Card, card.props);
|
|
});
|
|
this.setState({ cards: [...cardList] });
|
|
}
|
|
|
|
switchTo(value) {
|
|
CONFIG.activeTab = value;
|
|
localStorage.setItem(LOCALSTORAGE_KEYS.activeTab, value);
|
|
cardList = [];
|
|
requestPage = null;
|
|
this.setState({
|
|
cards: [],
|
|
rest: false,
|
|
endOfList: false,
|
|
});
|
|
endOfList = false;
|
|
|
|
this.newRequest(ITEMS_PER_REQUEST);
|
|
}
|
|
|
|
// This is called from loadAmount in a loop until it has the requested amount of cards or runs out of results
|
|
// Returns the next page number to fetch, or null if at end
|
|
// TODO: maybe we should rename `loadPage()`, since it's slightly confusing when we have github pages as well
|
|
async loadPage(queue) {
|
|
if (CONFIG.activeTab === "Extensions") {
|
|
let pageOfRepos = await getExtensionRepos(requestPage);
|
|
for (const repo of pageOfRepos.items) {
|
|
let extensions = await fetchExtensionManifest(repo.contents_url, repo.default_branch, repo.stargazers_count);
|
|
|
|
// I believe this stops the requests when switching tabs?
|
|
if (requestQueue.length > 1 && queue !== requestQueue[0]) {
|
|
// Stop this queue from continuing to fetch and append to cards list
|
|
return -1;
|
|
}
|
|
|
|
if (extensions && extensions.length) {
|
|
// console.log(`${repo.name} has ${extensions.length} extensions:`, extensions);
|
|
extensions.forEach((extension) => this.appendCard(extension, "extension"));
|
|
}
|
|
}
|
|
|
|
// First result is null or -1 so it coerces to 1
|
|
const currentPage = requestPage > -1 && requestPage ? requestPage : 1;
|
|
// Sets the amount of items that have thus been fetched
|
|
const soFarResults = ITEMS_PER_REQUEST * (currentPage - 1) + pageOfRepos.page_count;
|
|
const remainingResults = pageOfRepos.total_count - soFarResults;
|
|
|
|
// If still have more results, return next page number to fetch
|
|
console.log(`Parsed ${soFarResults}/${pageOfRepos.total_count} extensions`);
|
|
if (remainingResults > 0) return currentPage + 1;
|
|
else console.log("No more extension results");
|
|
} else if (CONFIG.activeTab === "Installed") {
|
|
const installedStuff = {
|
|
theme: getLocalStorageDataFromKey(LOCALSTORAGE_KEYS.installedThemes, []),
|
|
extension: getLocalStorageDataFromKey(LOCALSTORAGE_KEYS.installedExtensions, []),
|
|
snippet: getLocalStorageDataFromKey(LOCALSTORAGE_KEYS.installedSnippets, []),
|
|
};
|
|
|
|
for (const type in installedStuff) {
|
|
if (installedStuff[type].length) {
|
|
installedStuff[type].forEach(async (itemKey) => {
|
|
// TODO: err handling
|
|
const extension = JSON.parse(localStorage.getItem(itemKey));
|
|
// I believe this stops the requests when switching tabs?
|
|
if (requestQueue.length > 1 && queue !== requestQueue[0]) {
|
|
// Stop this queue from continuing to fetch and append to cards list
|
|
return -1;
|
|
}
|
|
|
|
// @ts-ignore
|
|
this.appendCard(extension, type);
|
|
});
|
|
}
|
|
}
|
|
|
|
// Don't need to return a page number because
|
|
// installed extension do them all in one go, since it's local
|
|
} else if (CONFIG.activeTab == "Themes") {
|
|
let pageOfRepos = await getThemeRepos(requestPage);
|
|
for (const repo of pageOfRepos.items) {
|
|
|
|
let themes = await fetchThemeManifest(repo.contents_url, repo.default_branch, repo.stargazers_count);
|
|
// I believe this stops the requests when switching tabs?
|
|
if (requestQueue.length > 1 && queue !== requestQueue[0]) {
|
|
// Stop this queue from continuing to fetch and append to cards list
|
|
return -1;
|
|
}
|
|
|
|
if (themes && themes.length) {
|
|
themes.forEach((theme) => this.appendCard(theme, "theme"));
|
|
}
|
|
}
|
|
|
|
// First request is null, so coerces to 1
|
|
const currentPage = requestPage > -1 && requestPage ? requestPage : 1;
|
|
// -1 because the page number is 1-indexed
|
|
const soFarResults = ITEMS_PER_REQUEST * (currentPage - 1) + pageOfRepos.page_count;
|
|
const remainingResults = pageOfRepos.total_count - soFarResults;
|
|
|
|
console.log(`Parsed ${soFarResults}/${pageOfRepos.total_count} themes`);
|
|
if (remainingResults > 0) return currentPage + 1;
|
|
else console.log("No more theme results");
|
|
} else if (CONFIG.activeTab == "Snippets") {
|
|
let snippets = await fetchCssSnippets();
|
|
|
|
if (requestQueue.length > 1 && queue !== requestQueue[0]) {
|
|
// Stop this queue from continuing to fetch and append to cards list
|
|
return -1;
|
|
}
|
|
if (snippets && snippets.length) {
|
|
snippets.forEach((snippet) => this.appendCard(snippet, "snippet"));
|
|
}
|
|
|
|
}
|
|
|
|
this.setState({ rest: true, endOfList: true });
|
|
endOfList = true;
|
|
return null;
|
|
}
|
|
/**
|
|
* Load a new set of extensions
|
|
* @param {any} queue An array of the extensions to be loaded
|
|
* @param {number} [quantity] Amount of extensions to be loaded per page. (Defaults to ITEMS_PER_REQUEST constant)
|
|
*/
|
|
async loadAmount(queue, quantity = ITEMS_PER_REQUEST) {
|
|
this.setState({ rest: false });
|
|
quantity += cardList.length;
|
|
|
|
requestPage = await this.loadPage(queue);
|
|
|
|
while (
|
|
requestPage &&
|
|
requestPage !== -1 &&
|
|
cardList.length < quantity &&
|
|
!this.state.endOfList
|
|
) {
|
|
requestPage = await this.loadPage(queue);
|
|
}
|
|
|
|
if (requestPage === -1) {
|
|
requestQueue = requestQueue.filter(a => a !== queue);
|
|
return;
|
|
}
|
|
|
|
// Remove this queue from queue list
|
|
requestQueue.shift();
|
|
this.setState({ rest: true });
|
|
}
|
|
|
|
/**
|
|
* Load more items if there are more items to load.
|
|
* @returns {void}
|
|
*/
|
|
loadMore() {
|
|
if (this.state.rest && !endOfList) {
|
|
this.loadAmount(requestQueue[0], ITEMS_PER_REQUEST);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update the colour schemes in the state + dropdown, and inject the active one
|
|
* @param {any} schemes Object with the colour schemes
|
|
* @param {string} activeScheme The name of the active colour scheme (a key in the schemes object)
|
|
*/
|
|
updateColourSchemes(schemes, activeScheme) {
|
|
console.log("updateColourSchemes", schemes, activeScheme);
|
|
CONFIG.theme.schemes = schemes;
|
|
CONFIG.theme.activeScheme = activeScheme;
|
|
|
|
if (schemes && schemes[activeScheme]) {
|
|
this.injectColourScheme(CONFIG.theme.schemes[activeScheme]);
|
|
} else {
|
|
// Reset schemes if none sent
|
|
this.injectColourScheme(null);
|
|
}
|
|
|
|
// Save to localstorage
|
|
const installedThemeKey = localStorage.getItem(LOCALSTORAGE_KEYS.themeInstalled);
|
|
const installedThemeDataStr = localStorage.getItem(installedThemeKey);
|
|
const installedThemeData = JSON.parse(installedThemeDataStr);
|
|
installedThemeData.activeScheme = activeScheme;
|
|
localStorage.setItem(installedThemeKey, JSON.stringify(installedThemeData));
|
|
|
|
this.setState({
|
|
schemes,
|
|
activeScheme,
|
|
});
|
|
}
|
|
|
|
// NOTE: Keep in sync with extension.js
|
|
injectColourScheme (scheme) {
|
|
// Remove any existing Spicetify scheme
|
|
const existingColorsCSS = document.querySelector("link[href='colors.css']");
|
|
if (existingColorsCSS) existingColorsCSS.remove();
|
|
|
|
// Remove any existing marketplace scheme
|
|
const existingMarketplaceSchemeCSS = document.querySelector("style.marketplaceCSS.marketplaceScheme");
|
|
if (existingMarketplaceSchemeCSS) existingMarketplaceSchemeCSS.remove();
|
|
|
|
if (scheme) {
|
|
// Add new marketplace scheme
|
|
const schemeTag = document.createElement("style");
|
|
schemeTag.classList.add("marketplaceCSS");
|
|
schemeTag.classList.add("marketplaceScheme");
|
|
|
|
let injectStr = ":root {";
|
|
const themeIniKeys = Object.keys(scheme);
|
|
themeIniKeys.forEach((key) => {
|
|
injectStr += `--spice-${key}: #${scheme[key]};`;
|
|
injectStr += `--spice-rgb-${key}: ${hexToRGB(scheme[key])};`;
|
|
});
|
|
injectStr += "}";
|
|
schemeTag.innerHTML = injectStr;
|
|
document.head.appendChild(schemeTag);
|
|
} else {
|
|
// Re-add default user.css
|
|
let originalColorsCSS = document.createElement("link");
|
|
originalColorsCSS.setAttribute("rel", "stylesheet");
|
|
originalColorsCSS.setAttribute("href", "colors.css");
|
|
originalColorsCSS.classList.add("userCSS");
|
|
document.head.appendChild(originalColorsCSS);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The componentDidMount() method is called when the component is first loaded.
|
|
* It checks if the cardList is already loaded. If it is, it checks if the lastScroll value is
|
|
greater than 0.
|
|
* If it is, it scrolls to the lastScroll value. If it isn't, it scrolls to the top of the page.
|
|
* If the cardList isn't loaded, it loads the cardList.
|
|
*/
|
|
async componentDidMount() {
|
|
gridUpdateTabs = this.updateTabs.bind(this);
|
|
gridUpdatePostsVisual = this.updatePostsVisual.bind(this);
|
|
|
|
const viewPort = document.querySelector(".os-viewport");
|
|
this.checkScroll = this.isScrolledBottom.bind(this);
|
|
viewPort.addEventListener("scroll", this.checkScroll);
|
|
|
|
if (cardList.length) { // Already loaded
|
|
if (lastScroll > 0) {
|
|
viewPort.scrollTo(0, lastScroll);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Load blacklist
|
|
BLACKLIST = await getBlacklist();
|
|
this.newRequest(ITEMS_PER_REQUEST);
|
|
}
|
|
|
|
/**
|
|
* When the component is unmounted, remove the scroll event listener.
|
|
* @returns {void}
|
|
*/
|
|
componentWillUnmount() {
|
|
gridUpdateTabs = gridUpdatePostsVisual = null;
|
|
const viewPort = document.querySelector(".os-viewport");
|
|
lastScroll = viewPort.scrollTop;
|
|
viewPort.removeEventListener("scroll", this.checkScroll);
|
|
}
|
|
|
|
/**
|
|
* If the user has scrolled to the bottom of the page, load more posts.
|
|
* @param event - The event object that is passed to the callback function.
|
|
* @returns {void}
|
|
*/
|
|
isScrolledBottom(event) {
|
|
const viewPort = event.target;
|
|
if ((viewPort.scrollTop + viewPort.clientHeight) >= viewPort.scrollHeight) {
|
|
// At bottom, load more posts
|
|
this.loadMore();
|
|
}
|
|
}
|
|
|
|
setActiveTheme(themeKey) {
|
|
CONFIG.theme.activeThemeKey = themeKey;
|
|
this.setState({ activeThemeKey: themeKey });
|
|
}
|
|
|
|
// TODO: clean this up. It worked when I was using state, but state seems like pointless overhead.
|
|
getActiveScheme() {
|
|
return this.state.activeScheme;
|
|
}
|
|
|
|
render() {
|
|
return react.createElement("section", {
|
|
className: "contentSpacing",
|
|
},
|
|
react.createElement("div", {
|
|
className: "marketplace-header",
|
|
}, react.createElement("h1", null, this.props.title),
|
|
// Start of marketplace-header__right
|
|
react.createElement("div", {
|
|
className: "marketplace-header__right",
|
|
},
|
|
// Show colour scheme dropdown if there is a theme with schemes installed
|
|
this.state.activeScheme ? react.createElement(SortBox, {
|
|
onChange: (value) => this.updateColourSchemes(this.state.schemes, value),
|
|
// TODO: Make this compatible with the changes to the theme install process: need to create a method to update the scheme options without a full reload.
|
|
sortBoxOptions: generateSchemesOptions(this.state.schemes),
|
|
// It doesn't work when I directly use CONFIG.theme.activeScheme in the sortBySelectedFn
|
|
// because it hardcodes the value into the fn
|
|
sortBySelectedFn: (a) => a.key === this.getActiveScheme(),
|
|
}) : null,
|
|
react.createElement("button", {
|
|
className: "marketplace-settings-button",
|
|
id: "marketplace-settings-button",
|
|
|
|
onClick: openConfig,
|
|
}, SETTINGS_ICON),
|
|
// End of marketplace-header__right
|
|
),
|
|
// TODO: Add search bar and sort functionality
|
|
// react.createElement("div", {
|
|
// className: "searchbar--bar__wrapper",
|
|
// }, react.createElement("input", {
|
|
// className: "searchbar-bar",
|
|
// type: "text",
|
|
// placeholder: "Search for Extensions?",
|
|
// })),
|
|
),
|
|
[ // Add a header and grid for each card type if it has any cards
|
|
{ handle: "extension", name: "Extensions" },
|
|
{ handle: "theme", name: "Themes" },
|
|
{ handle: "snippet", name: "Snippets" },
|
|
].map((cardType) => {
|
|
const cardsOfType = cardList.filter((card) => card.props.type === cardType.handle)
|
|
.map((card) => {
|
|
// Clone the cards and update the prop to trigger re-render
|
|
// TODO: is it possible to only re-render the theme cards whose status have changed?
|
|
const cardElement = react.cloneElement(card, {
|
|
activeThemeKey: this.state.activeThemeKey,
|
|
});
|
|
return cardElement;
|
|
});
|
|
|
|
if (cardsOfType.length) {
|
|
return [
|
|
// Add a header for the card type
|
|
react.createElement("h2",
|
|
{ className: "marketplace-card-type-heading" },
|
|
cardType.name),
|
|
// Add the grid and cards
|
|
react.createElement("div", {
|
|
className: "marketplace-grid main-gridContainer-gridContainer main-gridContainer-fixedWidth",
|
|
"data-tab": CONFIG.activeTab,
|
|
style: {
|
|
"--minimumColumnWidth": "180px",
|
|
"--column-width": "minmax(var(--minimumColumnWidth),1fr)",
|
|
"--column-count": "auto-fill",
|
|
"--grid-gap": "24px",
|
|
},
|
|
}, cardsOfType)];
|
|
} else {
|
|
return null;
|
|
}
|
|
}), react.createElement("footer", {
|
|
style: {
|
|
margin: "auto",
|
|
textAlign: "center",
|
|
},
|
|
}, !this.state.endOfList && (this.state.rest ? react.createElement(LoadMoreIcon, { onClick: this.loadMore.bind(this) }) : react.createElement(LoadingIcon)),
|
|
// Add snippets button if on snippets tab
|
|
CONFIG.activeTab === "Snippets" ? react.createElement("button", {
|
|
className: "marketplace-add-snippet-btn main-buttons-button main-button-secondary",
|
|
onClick: openAddSnippetModal,
|
|
}, "+Add CSS") : null,
|
|
), react.createElement(TopBarContent, {
|
|
switchCallback: this.switchTo.bind(this),
|
|
links: CONFIG.tabs,
|
|
activeLink: CONFIG.activeTab,
|
|
}));
|
|
}
|
|
}
|
|
|
|
// TODO: add sort type, order, etc?
|
|
// https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-for-repositories#search-by-topic
|
|
// https://docs.github.com/en/rest/reference/search#search-repositories
|
|
/**
|
|
* Query GitHub for all repos with the "spicetify-extensions" topic
|
|
* @param {number} page The query page number
|
|
* @returns Array of search results (filtered through the blacklist)
|
|
*/
|
|
async function getExtensionRepos(page = 1) {
|
|
// www is needed or it will block with "cross-origin" error.
|
|
let url = `https://api.github.com/search/repositories?q=${encodeURIComponent("topic:spicetify-extensions")}&per_page=${ITEMS_PER_REQUEST}`;
|
|
|
|
// We can test multiple pages with this URL (58 results), as well as broken iamges etc.
|
|
// let url = `https://api.github.com/search/repositories?q=${encodeURIComponent("topic:spicetify")}`;
|
|
if (page) url += `&page=${page}`;
|
|
// Sorting params (not implemented for Marketplace yet)
|
|
// if (sortConfig.by.match(/top|controversial/) && sortConfig.time) {
|
|
// url += `&t=${sortConfig.time}`
|
|
const allRepos = await fetch(url).then(res => res.json()).catch(() => []);
|
|
if (!allRepos.items) {
|
|
Spicetify.showNotification("Too Many Requests, Cool Down.");
|
|
}
|
|
const filteredResults = {
|
|
...allRepos,
|
|
// Include count of all items on the page, since we're filtering the blacklist below,
|
|
// which can mess up the paging logic
|
|
page_count: allRepos.items.length,
|
|
items: allRepos.items.filter(item => !BLACKLIST.includes(item.html_url)),
|
|
};
|
|
|
|
return filteredResults;
|
|
}
|
|
|
|
// TODO: add try/catch here?
|
|
// TODO: can we add a return type here?
|
|
/**
|
|
* Get the manifest object for a repo
|
|
* @param {string} user Owner username
|
|
* @param {string} repo Repo name
|
|
* @param {string} branch Default branch name (e.g. main or master)
|
|
* @returns The manifest object
|
|
*/
|
|
async function getRepoManifest(user, repo, branch) {
|
|
const sessionStorageItem = window.sessionStorage.getItem(`${user}-${repo}`);
|
|
const failedSessionStorageItems = window.sessionStorage.getItem("noManifests");
|
|
if (sessionStorageItem) {
|
|
return JSON.parse(sessionStorageItem);
|
|
}
|
|
const url = `https://raw.githubusercontent.com/${user}/${repo}/${branch}/manifest.json`;
|
|
if (failedSessionStorageItems.includes(url)) {
|
|
return null;
|
|
}
|
|
const manifest = await fetch(url).then(res => res.json()).catch(() => addToSessionStorage([url], "noManifests"));
|
|
if (manifest) {
|
|
window.sessionStorage.setItem(`${user}-${repo}`, JSON.stringify(manifest));
|
|
}
|
|
return manifest;
|
|
}
|
|
|
|
// TODO: can we add a return type here?
|
|
/**
|
|
* Fetch extensions from a repo and format data for generating cards
|
|
* @param {string} contents_url The repo's GitHub API contents_url (e.g. "https://api.github.com/repos/theRealPadster/spicetify-hide-podcasts/contents/{+path}")
|
|
* @param {string} branch The repo's default branch (e.g. main or master)
|
|
* @param {number} stars The number of stars the repo has
|
|
* @returns Extension info for card (or null)
|
|
*/
|
|
async function fetchExtensionManifest(contents_url, branch, stars) {
|
|
try {
|
|
// TODO: use the original search full_name ("theRealPadster/spicetify-hide-podcasts") or something to get the url better?
|
|
let manifests;
|
|
const regex_result = contents_url.match(/https:\/\/api\.github\.com\/repos\/(?<user>.+)\/(?<repo>.+)\/contents/);
|
|
// TODO: err handling?
|
|
if (!regex_result || !regex_result.groups) return null;
|
|
const { user, repo } = regex_result.groups;
|
|
|
|
manifests = await getRepoManifest(user, repo, branch);
|
|
|
|
// If the manifest returned is not an array, initialize it as one
|
|
if (!Array.isArray(manifests)) manifests = [manifests];
|
|
|
|
// Manifest is initially parsed
|
|
const parsedManifests = manifests.reduce((accum, manifest) => {
|
|
const selectedBranch = manifest.branch || branch;
|
|
const item = {
|
|
manifest,
|
|
title: manifest.name,
|
|
subtitle: manifest.description,
|
|
authors: processAuthors(manifest.authors, user),
|
|
user,
|
|
repo,
|
|
branch: selectedBranch,
|
|
|
|
imageURL: manifest.preview && manifest.preview.startsWith("http")
|
|
? manifest.preview
|
|
: `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.preview}`,
|
|
extensionURL: manifest.main.startsWith("http")
|
|
? manifest.main
|
|
: `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.main}`,
|
|
readmeURL: manifest.readme && manifest.readme.startsWith("http")
|
|
? manifest.readme
|
|
: `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.readme}`,
|
|
stars,
|
|
tags: manifest.tags,
|
|
};
|
|
|
|
// If manifest is valid, add it to the list
|
|
if (manifest && manifest.name && manifest.description && manifest.main
|
|
) {
|
|
// Add to list unless we're hiding installed items and it's installed
|
|
if (!(CONFIG.visual.hideInstalled
|
|
&& localStorage.getItem("marketplace:installed:" + `${user}/${repo}/${manifest.main}`))
|
|
) {
|
|
accum.push(item);
|
|
}
|
|
}
|
|
// else {
|
|
// console.error("Invalid manifest:", manifest);
|
|
// }
|
|
|
|
return accum;
|
|
}, []);
|
|
|
|
return parsedManifests;
|
|
}
|
|
catch (err) {
|
|
// console.warn(contents_url, err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// TODO: can we add a return type here?
|
|
/**
|
|
* Fetch themes from a repo and format data for generating cards
|
|
* @param {string} contents_url The repo's GitHub API contents_url (e.g. "https://api.github.com/repos/theRealPadster/spicetify-hide-podcasts/contents/{+path}")
|
|
* @param {string} branch The repo's default branch (e.g. main or master)
|
|
* @param {number} stars The number of stars the repo has
|
|
* @returns Extension info for card (or null)
|
|
*/
|
|
async function fetchThemeManifest(contents_url, branch, stars) {
|
|
try {
|
|
let manifests;
|
|
const regex_result = contents_url.match(/https:\/\/api\.github\.com\/repos\/(?<user>.+)\/(?<repo>.+)\/contents/);
|
|
// TODO: err handling?
|
|
if (!regex_result || !regex_result.groups) return null;
|
|
let { user, repo } = regex_result.groups;
|
|
|
|
manifests = await getRepoManifest(user, repo, branch);
|
|
|
|
// If the manifest returned is not an array, initialize it as one
|
|
if (!Array.isArray(manifests)) manifests = [manifests];
|
|
|
|
// Manifest is initially parsed
|
|
const parsedManifests = manifests.reduce((accum, manifest) => {
|
|
const selectedBranch = manifest.branch || branch;
|
|
const item = {
|
|
manifest,
|
|
title: manifest.name,
|
|
subtitle: manifest.description,
|
|
authors: processAuthors(manifest.authors, user),
|
|
user,
|
|
repo,
|
|
branch: selectedBranch,
|
|
imageURL: manifest.preview && manifest.preview.startsWith("http")
|
|
? manifest.preview
|
|
: `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.preview}`,
|
|
readmeURL: manifest.readme && manifest.readme.startsWith("http")
|
|
? manifest.readme
|
|
: `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.readme}`,
|
|
stars,
|
|
tags: manifest.tags,
|
|
// theme stuff
|
|
cssURL: manifest.usercss.startsWith("http")
|
|
? manifest.usercss
|
|
: `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.usercss}`,
|
|
// TODO: clean up indentation etc
|
|
schemesURL: manifest.schemes
|
|
? (
|
|
manifest.schemes.startsWith("http") ? manifest.schemes : `https://raw.githubusercontent.com/${user}/${repo}/${selectedBranch}/${manifest.schemes}`
|
|
)
|
|
: null,
|
|
include: manifest.include,
|
|
};
|
|
// If manifest is valid, add it to the list
|
|
if (manifest && manifest.name && manifest.usercss && manifest.description) {
|
|
accum.push(item);
|
|
}
|
|
return accum;
|
|
}, []);
|
|
return parsedManifests;
|
|
}
|
|
catch (err) {
|
|
// console.warn(contents_url, err);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Query the GitHub API for a page of theme repos (having "spicetify-themes" topic)
|
|
* @param {number} page The page to get (defaults to 1)
|
|
* @returns Array of GitHub API results, filtered through the blacklist
|
|
*/
|
|
async function getThemeRepos(page = 1) {
|
|
let url = `https://api.github.com/search/repositories?q=${encodeURIComponent("topic:spicetify-themes")}&per_page=${ITEMS_PER_REQUEST}`;
|
|
|
|
// We can test multiple pages with this URL (58 results), as well as broken iamges etc.
|
|
// let url = `https://api.github.com/search/repositories?q=${encodeURIComponent("topic:spicetify")}`;
|
|
if (page) url += `&page=${page}`;
|
|
// Sorting params (not implemented for Marketplace yet)
|
|
// if (sortConfig.by.match(/top|controversial/) && sortConfig.time) {
|
|
// url += `&t=${sortConfig.time}`
|
|
const allThemes = await fetch(url).then(res => res.json()).catch(() => []);
|
|
if (!allThemes.items) {
|
|
Spicetify.showNotification("Too Many Requests, Cool Down.");
|
|
}
|
|
const filteredResults = {
|
|
...allThemes,
|
|
// Include count of all items on the page, since we're filtering the blacklist below,
|
|
// which can mess up the paging logic
|
|
page_count: allThemes.items.length,
|
|
items: allThemes.items.filter(item => !BLACKLIST.includes(item.html_url)),
|
|
};
|
|
|
|
return filteredResults;
|
|
}
|
|
function addToSessionStorage(items, key) {
|
|
if (!items || items == null) return;
|
|
items.forEach(item => {
|
|
if (!key) key = `${items.user}-${items.repo}`;
|
|
// If the key already exists, it will append to it instead of overwriting it
|
|
const existing = window.sessionStorage.getItem(key);
|
|
const parsed = existing ? JSON.parse(existing) : [];
|
|
parsed.push(item);
|
|
window.sessionStorage.setItem(key, JSON.stringify(parsed));
|
|
});
|
|
}
|