merge in main, move pagination setting for consistency

This commit is contained in:
Kendall Garner 2022-07-11 13:28:05 -04:00
commit 74429ceb7b
No known key found for this signature in database
GPG key ID: 18D2767419676C87
48 changed files with 3512 additions and 2571 deletions

View file

@ -80,6 +80,12 @@ jobs:
sudo dpkg --add-architecture i386
sudo apt-get update -y
sudo apt-get install -y wine32
- run:
name: Reinstall proper rust node module
command: |
cd ./node_modules/cider_utils
yarn run prebuild-downloads --platform=win32 --verbose
cd ../..
- run:
name: Generate Builds (Windows)
command: yarn electron-builder -w --x64 -p never
@ -105,6 +111,12 @@ jobs:
sudo dpkg --add-architecture i386
sudo apt-get update -y
sudo apt-get install -y wine32
- run:
name: Reinstall proper rust node module
command: |
cd ./node_modules/cider_utils
yarn run prebuild-downloads --platform=win32 --verbose
cd ../..
- run:
name: Generate Builds (Winget)
command: yarn electron-builder --win -c winget.json -p never
@ -147,6 +159,7 @@ jobs:
- run:
name: Publish Release
command: |
echo "Creating release for Cider v${APP_VERSION} on the ${CIRCLE_BRANCH} branch."
gh release create "v${APP_VERSION}" --title "Cider Version ${APP_VERSION} (${CIRCLE_BRANCH})" --generate-notes -R ciderapp/cider-releases ~/Cider/dist/artifacts/*.deb ~/Cider/dist/artifacts/*.AppImage ~/Cider/dist/artifacts/*.snap ~/Cider/dist/artifacts/*.exe ~/Cider/dist/artifacts/*.yml ~/Cider/dist/artifacts/*.blockmap
# Orchestrate our job run sequence

View file

@ -96,6 +96,7 @@ jobs:
cp resources/macPackager.js node_modules/app-builder-lib/out/macPackager.js
rm -r node_modules/pouchdb-node/node_modules/leveldown
rm -r node_modules/pouchdb-adapter-leveldb/node_modules/leveldown
rm -r /node_modules/leveldown/node_modules/node-gyp-build || true
yarn dist:universalNotWorking -p never
# - name: Perform CodeQL Analysis
# uses: github/codeql-action/analyze@v1

1
.gitignore vendored
View file

@ -330,3 +330,4 @@ savedconfig/config.json
savedconfig/session.json
savedconfig/window-state.json
src/main/base/sample.json

View file

@ -64,7 +64,7 @@
"leveldown": "^6.1.1",
"mdns-js": "git+https://github.com/ciderapp/node-mdns-js.git",
"mpris-service": "^2.1.2",
"music-metadata": "^7.12.3",
"music-metadata": "^7.12.4",
"node-gyp": "^9.0.0",
"node-ssdp": "^4.0.1",
"pouchdb-adapter-leveldb": "^7.3.0",
@ -80,7 +80,8 @@
"wallpaper": "5.0.1",
"ws": "^8.5.0",
"xml2js": "^0.4.23",
"youtube-search-without-api-key": "^1.0.7"
"youtube-search-without-api-key": "^1.0.7",
"cider_utils": "git+https://github.com/ciderapp/cider_utils"
},
"devDependencies": {
"@types/adm-zip": "^0.5.0",
@ -121,9 +122,9 @@
}
],
"build": {
"electronVersion": "18.3.3",
"electronVersion": "18.3.5",
"electronDownload": {
"version": "18.3.3+wvcus",
"version": "18.3.5+wvcus",
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
},
"appId": "cider",

View file

@ -24,9 +24,10 @@ exports.default = function(context) {
// execSync('python3 -m castlabs_evs.vmp -n sign-pkg dist/mac',{stdio: 'inherit'})
// if (fs.existsSync('dist/mac-arm64'))
// execSync('python3 -m castlabs_evs.vmp -n sign-pkg dist/mac-arm64 -z',{stdio: 'inherit'})
// if (fs.existsSync('dist/mac-x64'))
// execSync('python3 -m castlabs_evs.vmp -n sign-pkg dist/mac-x64',{stdio: 'inherit'})
if (fs.existsSync('dist/mac-x64') || fs.existsSync('dist/mac-universal--x64') )
execSync('cd ./node_modules/cider_utils; yarn run prebuild-downloads --platform=darwin --arch=arm64 --verbose; cd ../..',{stdio: 'inherit'})
// console.log('VMP signing complete')
}
}

View file

@ -515,3 +515,9 @@ Update 21/06/2022 20:39 UTC
Update 23/06/2022 04:00 UTC
* `settings.option.connectivity.lastfmScrobble.filterTypes`: Added to `en_US`
Update 03/07/2022 20:00 UTC
* `term.plugins`: Added to `en_US`
* `settings.header.visual.styles`: Added to `en_US`

View file

@ -394,5 +394,10 @@
"action.cut": "Ausschneiden",
"action.paste": "Einfügen",
"action.selectAll": "Alles auswählen",
"action.delete": "Löschen"
"action.delete": "Löschen",
"home.syncFavorites": "Sync Favoriten",
"term.quit" : "Beenden",
"settings.option.connectivity.lastfmScrobble.filterLoop.description": "Verhindert, dass geloopte Titel gescrobbelt oder in der (Hört Gerade)-Liste auf Last.fm angezeigt werden",
"settings.option.connectivity.lastfmScrobble.filterTypes": "Medientypen filtern (Last.fm)",
"settings.option.connectivity.lastfmScrobble.manualToken": "Last.fm-Token manuell eingeben"
}

View file

@ -31,6 +31,10 @@
"term.miniplayer": "MiniPlayer",
"term.history": "History",
"term.search": "Search",
"term.scroll": "Scroll Mode",
"term.scroll.infinite": "Infinite",
"term.scroll.paged": "${songsPerPage} per page",
"term.live": "LIVE",
"term.showSearch": "Show search bar",
"term.hideSearch": "Hide search bar",
"term.library": "Library",
@ -90,9 +94,6 @@
"term.size": "Size",
"term.size.normal": "Normal",
"term.size.compact": "Compact",
"term.scroll": "Scroll Mode",
"term.scroll.infinite": "Infinite",
"term.scroll.paged": "${songsPerPage} per page",
"term.enable": "Enable",
"term.disable": "Disable",
"term.enabled": "Enabled",
@ -139,7 +140,6 @@
"term.recentStations": "Recent Stations",
"term.personalStations": "Personal Stations",
"term.amLive": "Apple Music Live",
"term.live": "LIVE",
"term.language": "Language",
"term.funLanguages": "Fun",
"term.noLyrics": "Instrumental Track / No Lyrics.",
@ -184,8 +184,9 @@
"term.top": "Top",
"term.version": "Version",
"term.noVideos": "No videos found.",
"term.plugin": "Plug-in",
"term.pluginMenu": "Plug-in Menu",
"term.plugins": "Plugins",
"term.plugin": "Plugin",
"term.pluginMenu": "Plugins Menu",
"term.pluginMenu.none": "No interactive plugins",
"term.replay": "Replay",
"term.uniqueAlbums": "Unique Albums",
@ -200,7 +201,7 @@
"term.confirmLogout": "Are you sure you want to logout?",
"term.creditDesignedBy": "Designed by ${authorUsername}",
"term.discNumber": "Disc ${discNumber}",
"term.reload" : "Reload Cider ?",
"term.reload" : "Reload Cider?",
"term.toggleprivate" : "Toggle Private Session",
"term.webremote" : "Web Remote",
"term.cast" : "Cast",
@ -213,6 +214,9 @@
"term.nowPlaying": "Now Playing",
"home.syncFavorites": "Sync Favorites",
"home.syncFavorites.gettingArtists": "Getting Favorited Artists...",
"action.favorite": "Favorite",
"action.removeFavorite": "Remove Favorite",
"action.refresh": "Refresh",
"home.title": "Home",
"home.recentlyPlayed": "Recently Played",
"home.recentlyAdded": "Recently Added",
@ -233,8 +237,6 @@
"podcast.episodes": "Episodes",
"podcast.playEpisode": "Play Episode",
"podcast.website": "Podcast Website",
"action.favorite": "Favorite",
"action.removeFavorite": "Remove Favorite",
"action.hideLibrary": "Hide Library",
"action.showLibrary": "Show Library",
"action.cut": "Cut",
@ -308,7 +310,6 @@
"action.createNew": "Create New...",
"action.openArtworkInBrowser": "Open artwork in browser",
"action.scrollToTop": "Scroll to top",
"action.refresh": "Refresh",
"menubar.options.view": "View",
"menubar.options.reload": "Reload",
"menubar.options.forcereload": "Force Reload",
@ -421,9 +422,9 @@
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.E168_1": "Jasmine Macchiato",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z3600": "Hokkaido Milk Tea",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500A": "Moonlight Softcake",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.BSCBM": "Brown Sugar Creme Brûlée Milk",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500B": "Clafoutis aux Cerises",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500C": "Uji Matcha Mochi",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.BSCBM": "Brown Sugar Creme Brûlée Milk",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.CUDDLE": "Cuddle Warmth",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Enhances the perceived audio quality of AAC encoded audio by using a real-time algorithm that takes advantage of both psychoacoustic models of human hearing and AAC encoding characteristics.",
@ -457,15 +458,10 @@
"settings.header.visual": "Visual",
"settings.header.visual.description": "Adjust the visual settings for Cider.",
"settings.option.visual.windowStyle": "Window Style",
"settings.option.visual.customAccentColor": "Custom Accent Color",
"settings.option.visual.accentColor": "Accent Color",
"settings.option.visual.purplePodcastPlaybackBar": "Purple Playback Bar for Podcasts",
"settings.option.visual.windowColor": "Window Tint Color",
"settings.option.visual.windowBackgroundStyle": "Window Background Style",
"settings.header.visual.windowBackgroundStyle.none": "None",
"settings.header.visual.windowBackgroundStyle.artwork": "Artwork",
"settings.header.visual.windowBackgroundStyle.image": "Image",
"settings.header.visual.windowBackgroundStyle.color": "Color Tint",
"settings.option.visual.animatedArtwork": "Animated Artwork",
"settings.header.visual.animatedArtwork.always": "Always",
"settings.header.visual.animatedArtwork.limited": "Limited to pages and special entries",
@ -491,6 +487,7 @@
"settings.prompt.visual.theme.github.URL": "Enter the URL of the theme you want to install",
"settings.prompt.visual.theme.uninstallTheme": "Are you sure you want to uninstall {{ theme }}?",
"settings.option.visual.theme.checkForUpdates": "Check for updates",
"settings.header.visual.styles": "Styles",
"settings.option.visual.theme.manageStyles": "Manage Styles",
"settings.option.visual.theme.uninstall": "Uninstall",
"settings.option.visual.theme.viewInfo": "View Info",
@ -559,11 +556,17 @@
"settings.option.experimental.unknownPlugin.description": "Allow installation of plugins from repos other than the Cider Plugin Repository",
"settings.option.experimental.compactUI": "Compact UI",
"settings.option.window.close_button_hide": "Close Button Should Hide the Application",
"settings.option.window.maxElementScale": "Maximum Element Scale",
"settings.option.experimental.inline_playlists": "Inline Playlists and Albums",
"settings.option.advanced.playlistTrackMapping": "Playlist Track Mapping",
"settings.option.advanced.playlistTrackMapping.description": "Enables deep scanning of playlists to determine which tracks are in which playlists. Playlist cache build times can increase significantly.",
"settings.option.visual.transparent": "Transparent frame",
"settings.option.visual.transparent.description": "needs Theme Support, requires relaunch",
"settings.option.visual.customAccentColor": "Custom Accent Color",
"settings.option.visual.accentColor": "Accent Color",
"settings.option.visual.purplePodcastPlaybackBar": "Purple Playback Bar for Podcasts",
"settings.option.visual.windowColor": "Window Tint Color",
"settings.header.visual.windowBackgroundStyle.color": "Color Tint",
"settings.header.advanced": "Advanced",
"settings.header.connect": "Sync",
"settings.option.connect.link_account": "Enable Sync with Cider Connect",
@ -640,4 +643,4 @@
"oobe.visual.suggestingThemes.community3": "Dracula",
"oobe.visual.suggestingThemes.community3.text": "The iconic Dracula color scheme.",
"oobe.amsignin.title": ""
}
}

View file

@ -31,6 +31,10 @@
"term.miniplayer": "MiniPlayer",
"term.history": "History",
"term.search": "Search",
"term.scroll": "Scroll Mode",
"term.scroll.infinite": "Infinite",
"term.scroll.paged": "${songsPerPage} per page",
"term.live": "LIVE",
"term.showSearch": "Show search bar",
"term.hideSearch": "Hide search bar",
"term.library": "Library",
@ -180,8 +184,9 @@
"term.top": "Top",
"term.version": "Version",
"term.noVideos": "No videos found.",
"term.plugin": "Plug-in",
"term.pluginMenu": "Plug-in Menu",
"term.plugins": "Plugins",
"term.plugin": "Plugin",
"term.pluginMenu": "Plugins Menu",
"term.pluginMenu.none": "No interactive plugins",
"term.replay": "Replay",
"term.uniqueAlbums": "Unique Albums",
@ -196,7 +201,7 @@
"term.confirmLogout": "Are you sure you want to logout?",
"term.creditDesignedBy": "Designed by ${authorUsername}",
"term.discNumber": "Disc ${discNumber}",
"term.reload" : "Reload Cider ?",
"term.reload" : "Reload Cider?",
"term.toggleprivate" : "Toggle Private Session",
"term.webremote" : "Web Remote",
"term.cast" : "Cast",
@ -206,6 +211,12 @@
"term.zoomout" : "Zoom Out",
"term.zoomreset" : "Reset Zoom",
"term.fullscreen" : "Fullscreen",
"term.nowPlaying": "Now Playing",
"home.syncFavorites": "Sync Favorites",
"home.syncFavorites.gettingArtists": "Getting Favorited Artists...",
"action.favorite": "Favorite",
"action.removeFavorite": "Remove Favorite",
"action.refresh": "Refresh",
"home.title": "Home",
"home.recentlyPlayed": "Recently Played",
"home.recentlyAdded": "Recently Added",
@ -410,6 +421,8 @@
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z3600": "Hokkaido Milk Tea",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500A": "Moonlight Softcake",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.BSCBM": "Brown Sugar Creme Brûlée Milk",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500B": "Clafoutis aux Cerises",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500C": "Uji Matcha Mochi",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.CUDDLE": "Cuddle Warmth",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider Adrenaline Processor™",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Enhances the perceived audio quality of AAC encoded audio by using a real-time algorithm that takes advantage of both psychoacoustic models of human hearing and AAC encoding characteristics.",
@ -472,6 +485,7 @@
"settings.prompt.visual.theme.github.URL": "Enter the URL of the theme you want to install",
"settings.prompt.visual.theme.uninstallTheme": "Are you sure you want to uninstall {{ theme }}?",
"settings.option.visual.theme.checkForUpdates": "Check for updates",
"settings.header.visual.styles": "Styles",
"settings.option.visual.theme.manageStyles": "Manage Styles",
"settings.option.visual.theme.uninstall": "Uninstall",
"settings.option.visual.theme.viewInfo": "View Info",
@ -540,11 +554,17 @@
"settings.option.experimental.unknownPlugin.description": "Allow installation of plugins from repos other than the Cider Plugin Repository",
"settings.option.experimental.compactUI": "Compact UI",
"settings.option.window.close_button_hide": "Close Button Should Hide the Application",
"settings.option.window.maxElementScale": "Maximum Element Scale",
"settings.option.experimental.inline_playlists": "Inline Playlists and Albums",
"settings.option.advanced.playlistTrackMapping": "Playlist Track Mapping",
"settings.option.advanced.playlistTrackMapping.description": "Enables deep scanning of playlists to determine which tracks are in which playlists. Playlist cache build times can increase significantly.",
"settings.option.visual.transparent": "Transparent frame",
"settings.option.visual.transparent.description": "needs Theme Support, requires relaunch",
"settings.option.visual.customAccentColor": "Custom Accent Color",
"settings.option.visual.accentColor": "Accent Color",
"settings.option.visual.purplePodcastPlaybackBar": "Purple Playback Bar for Podcasts",
"settings.option.visual.windowColor": "Window Tint Color",
"settings.header.visual.windowBackgroundStyle.color": "Color Tint",
"settings.header.advanced": "Advanced",
"settings.header.connect": "Sync",
"settings.option.connect.link_account": "Enable Sync with Cider Connect",
@ -621,4 +641,4 @@
"oobe.visual.suggestingThemes.community3": "Dracula",
"oobe.visual.suggestingThemes.community3.text": "The iconic Dracula color scheme.",
"oobe.amsignin.title": ""
}
}

View file

@ -2,7 +2,7 @@
"i18n.languageName": "简体中文(中国)",
"i18n.languageNameEnglish": "Simp. Chinese (China)",
"i18n.category": "main",
"i18n.authors": "@notmaikiwi @BillKerman @jay900604",
"i18n.authors": "@notmaikiwi @BillKerman @jay900604 @sakura0224",
"app.name": "Cider",
"date.format": "${y}年${m}月${d}日",
"dialog.cancel": "取消",
@ -21,17 +21,22 @@
"term.accountSettings": "账户设置",
"term.logout": "退出登录",
"term.login": "登录",
"term.quickNav":"快速导航",
"term.cast":"投射",
"term.quickNav": "快速导航",
"term.about": "关于",
"term.privateSession": "隐身聆听",
"term.disablePrivateSession":"停止隐身聆听",
"term.autoplay":"自动播放",
"term.lyrics": "歌词",
"term.disablePrivateSession": "停止隐身聆听",
"term.queue": "待播清单",
"term.history": "历史记录",
"term.autoplay": "自动播放",
"term.lyrics": "歌词",
"term.miniplayer": "迷你播放器",
"term.history": "历史记录",
"term.search": "搜索",
"term.scroll": "滚动模式",
"term.scroll.infinite": "无限制",
"term.scroll.paged": "每页${songsPerPage}首",
"term.live": "LIVE",
"term.showSearch": "显示搜索栏",
"term.hideSearch": "隐藏搜索栏",
"term.library": "资料库",
"term.listenNow": "现在就听",
"term.browse": "浏览",
@ -42,23 +47,24 @@
"term.artists": "艺人",
"term.podcasts": "播客",
"term.playlists": "播放列表",
"term.charts":"排行榜",
"term.charts": "排行榜",
"term.playlist": "播放列表",
"term.newPlaylist": "新播放列表",
"term.newPlaylistFolder": "新播放列表文件夹",
"term.createNewPlaylist": "新建播放列表",
"term.createNewPlaylistFolder": "新建播放列表文件夹",
"term.deletePlaylist": "您确定要删除该播放列表吗?",
"term.navigateBack":"上一页",
"term.navigateForward":"下一页",
"term.navigateBack": "上一页",
"term.navigateForward": "下一页",
"term.play": "播放",
"term.playpause": "播放/暂停",
"term.pause": "暂停",
"term.stop": "停止",
"term.previous": "上一首",
"term.next": "下一首",
"term.shuffle": "随机播放",
"term.enableShuffle":"开启随机播放",
"term.disableShuffle":"关闭随机播放",
"term.enableShuffle": "开启随机播放",
"term.disableShuffle": "关闭随机播放",
"term.repeat": "循环播放",
"term.enableRepeatOne": "开启单曲循环",
"term.disableRepeatOne": "关闭单曲循环",
@ -67,7 +73,7 @@
"term.mute": "静音",
"term.unmute": "解除静音",
"term.share": "分享",
"term.share.success": "已拷到剪贴板",
"term.share.success": "已拷到剪贴板",
"term.settings": "设置",
"term.seeAll": "查看全部",
"term.sortBy": "排序",
@ -77,14 +83,14 @@
"term.sortBy.genre": "类型",
"term.sortBy.releaseDate": "发行日期",
"term.sortBy.duration": "时长",
"term.sortBy.dateAdded":"加入日期",
"term.sortBy.dateAdded": "加入日期",
"term.sortOrder": "字母排序",
"term.sortOrder.ascending": "升序",
"term.sortOrder.descending": "倒序",
"term.viewAs": "显示模式",
"term.viewAs.coverArt": "专辑封面",
"term.viewAs.list": "列表",
"term.dynamic":"动态",
"term.dynamic": "动态",
"term.size": "大小",
"term.size.normal": "正常",
"term.size.compact": "紧凑",
@ -106,6 +112,8 @@
"term.time.added": "添加于",
"term.time.released": "发行于",
"term.time.updated": "更新于",
"term.time.days": "天",
"term.time.day": "天",
"term.time.hours": "小时",
"term.time.hour": "小时",
"term.time.minutes": "分钟",
@ -118,8 +126,8 @@
"term.audioSettings": "音频设置",
"term.clearAll": "清空",
"term.recentStations": "最近播放的广播",
"term.personalStations":"最近播放的个人广播",
"term.amLive":"amLive",
"term.personalStations": "最近播放的个人广播",
"term.amLive": "Apple Music Live",
"term.language": "语言",
"term.funLanguages": "恶搞",
"term.noLyrics": "加载中... / 无搜索结果 / 纯音乐",
@ -133,13 +141,11 @@
"term.contributors": "贡献者",
"term.equalizer": "均衡器",
"term.reset": "重置",
"term.track": {
"one": "首歌曲",
"other": "首歌曲"
},
"term.tracks": "歌曲",
"term.track": "首歌曲",
"term.videos": "音乐视频",
"term.menu": "菜单",
"term.themeManaged": "由主题所管理",
"term.check": "检查",
"term.aboutArtist": "关于{{artistName}}",
"term.topResult": "热门搜索结果",
@ -155,30 +161,47 @@
"term.song.link.generate": "获取 song.link 共享链接...",
"term.musicVideos": "音乐视频",
"term.stations": "电台",
"term.curators": "策展人",
"term.appleCurators": "Apple 策展人",
"term.radioShows": "广播单集",
"term.recordLabels": "唱片公司",
"term.videoExtras": "视频特辑",
"term.top":"顶部",
"term.top": "顶部",
"term.version": "版本",
"term.noVideos":"无视频",
"term.noVideos": "无视频",
"term.plugins": "插件",
"term.plugin": "插件",
"term.pluginMenu": "插件菜单",
"term.pluginMenu.none": "沒有交互式插件",
"term.replay":"音乐回忆",
"term.uniqueAlbums":"Unique Albums",
"term.uniqueArtists":"Unique Artists",
"term.uniqueSongs":"Unique Songs",
"term.topArtists":"热门艺人",
"term.listenedTo":"听过",
"term.times":"次",
"term.topAlbums":"热门专辑",
"term.plays":"次",
"term.topGenres":"热门类型",
"term.confirmLogout":"你确定要退出登录吗?",
"term.creditDesignedBy":"由 ${authorUsername} 设计",
"term.discNumber":"碟 ${discNumber}",
"term.replay": "音乐回忆",
"term.uniqueAlbums": "独特专辑",
"term.uniqueArtists": "超绝艺人",
"term.uniqueSongs": "别致单曲",
"term.topArtists": "热门艺人",
"term.listenedTo": "听过",
"term.times": "次",
"term.topAlbums": "热门专辑",
"term.plays": "次",
"term.topGenres": "热门类型",
"term.confirmLogout": "你确定要退出登录吗?",
"term.creditDesignedBy": "由 ${authorUsername} 设计",
"term.discNumber": "碟 ${discNumber}",
"term.reload" : "重新载入 Cider?",
"term.toggleprivate": "切换隐身聆听",
"term.webremote": "远程控制",
"term.cast": "投射",
"term.cast2" : "投射到设备",
"term.quit" : "退出应用",
"term.zoomin" : "放大",
"term.zoomout" : "缩小",
"term.zoomreset" : "重置缩放",
"term.fullscreen" : "全屏模式",
"term.nowPlaying": "正在播放",
"home.syncFavorites": "同步喜爱艺人",
"home.syncFavorites.gettingArtists": "获取喜爱艺人...",
"action.favorite": "喜爱",
"action.removeFavorite": "取消喜爱",
"action.refresh": "刷新",
"home.title": "主页",
"home.recentlyPlayed": "最近播放",
"home.recentlyAdded": "最近添加",
@ -199,16 +222,15 @@
"podcast.episodes": "单集",
"podcast.playEpisode": "播放单集",
"podcast.website": "Podcast 网站",
"action.favorite":"喜爱",
"action.removeFavorite":"取消喜爱",
"action.hideLibrary":"隐藏资料库",
"action.showLibrary":"显示资料可查",
"action.cut":"剪切",
"action.paste":"粘贴",
"action.selectAll":"全选",
"action.delete":"删除",
"action.hideLibrary": "隐藏资料库",
"action.showLibrary": "显示资料库",
"action.cut": "剪切",
"action.paste": "粘贴",
"action.selectAll": "全选",
"action.delete": "删除",
"action.edit": "编辑",
"action.done": "完成",
"action.submit": "提交",
"action.editTracklist": "编辑歌曲清单",
"action.addToLibrary": "加入资料库",
"action.addToLibrary.success": "成功加入资料库",
@ -224,7 +246,7 @@
"action.createPlaylist": "新建播放列表",
"action.addToPlaylist": "添加到播放列表",
"action.removeFromPlaylist": "从播放列表移除",
"action.addToFavorites": "加至收藏",
"action.addToFavorites": "加至收藏",
"action.follow": "关注",
"action.follow.success": "已关注",
"action.follow.error": "尝试关注的过程发生了错误",
@ -236,7 +258,7 @@
"action.startRadio": "开始电台",
"action.goToArtist": "前往艺人",
"action.goToAlbum": "前往专辑",
"action.showInPlaylist":"在播放列表中显示",
"action.showInPlaylist": "在播放列表中显示",
"action.showInAppleMusic": "在 Apple Music 中显示",
"action.moveToTop": "移到顶部",
"action.share": "分享歌曲",
@ -253,11 +275,7 @@
"action.export": "导出",
"action.showAlbum": "显示专辑",
"action.tray.minimize": "最小化",
"action.tray.quit": "退出",
"action.tray.show": "显示 Cider",
"action.tray.playpause": "播放/暂停",
"action.tray.next": "下一首",
"action.tray.previous": "上一首",
"action.tray.listento": "Listen To:",
"action.update": "更新",
"action.install": "安装",
@ -266,7 +284,7 @@
"action.deletepreset": "删除默认",
"action.open": "打开",
"action.close": "关闭",
"action.relaunch.confirm":"你想重新启动 Cider 吗?",
"action.relaunch.confirm": "你想重新启动 Cider 吗?",
"action.cast.chromecast": "Chromecast",
"action.cast.todevices": "投射到设备",
"action.cast.stop": "停止投射到所有设备",
@ -277,49 +295,29 @@
"action.createNew": "添加...",
"action.openArtworkInBrowser": "在浏览器中打开专辑封面",
"action.scrollToTop": "回到顶部",
"menubar.options.about": "关于",
"menubar.options.settings": "设置",
"menubar.options.quit": "退出 Cider",
"menubar.options.view": "查看 ",
"menubar.options.reload": "重新载入",
"menubar.options.forcereload": "强制重新载入",
"menubar.options.toggledevtools": "切换开发人员工具",
"menubar.options.window": "窗口",
"menubar.options.minimize": "最小化",
"menubar.options.toggleprivate": "切换隐身聆听",
"menubar.options.webremote": "远程控制",
"menubar.options.audio": "音频设定",
"menubar.options.plugins": "插件目录",
"menubar.options.controls": "控制",
"menubar.options.next": "下一首",
"menubar.options.playpause": "播放/暂停",
"menubar.options.previous": "上一首",
"menubar.options.volumeup": "增大音量",
"menubar.options.volumedown": "减小音量",
"menubar.options.browse": "浏览",
"menubar.options.artists": "艺人",
"menubar.options.search": "搜索",
"menubar.options.albums": "专辑",
"menubar.options.cast": "投射至设备",
"menubar.options.account": "账户",
"menubar.options.accountsettings": "账户设置",
"menubar.options.signout": "注销",
"menubar.options.support": "支持",
"menubar.options.discord": "Discord",
"menubar.options.github": "GitHub Wiki",
"menubar.options.report": "报告...",
"menubar.options.bug": "Bug",
"menubar.options.feature": "功能请求",
"menubar.options.trans": "翻译报告/请求",
"menubar.options.license": "查看授权",
"menubar.options.conf": "在编辑器打开配置文件",
"menubar.options.listennow": "现在就听",
"menubar.options.recentlyAdded": "最近添加",
"menubar.options.songs": "歌曲",
"menubar.options.zoom": "缩放",
"settings.header.general": "通用",
"settings.header.general.description": "调整 Cider 的通用设置",
"settings.option.audio.volumeStep": "音量改变量",
"settings.option.audio.maxVolume": "最大音量",
"settings.option.general.language": "语言",
"settings.option.general.resumebehavior": "恢复行为",
"settings.option.general.resumebehavior.description": "会影响你回到 Cider 应用程序时,恢复歌曲的方式。",
"settings.option.general.resumebehavior.locally": "本地",
@ -330,61 +328,66 @@
"settings.option.general.resumetabs.description": "你可以选择启动 Cider 时要默认打开的页面。",
"settings.option.general.resumetabs.dynamic": "动态",
"settings.option.general.resumetabs.dynamic.description": "Cider 将自动打开你上次停留的页面。",
"settings.option.general.language": "语言",
"settings.option.general.language.main": "语言",
"settings.option.general.language.fun": "恶搞语言",
"settings.option.general.language.unsorted": "未分类",
"settings.option.general.customizeSidebar": "自定义侧边栏的功能",
"settings.option.general.customizeSidebar.customize": "自定义",
"settings.option.general.keybindings": "快捷操作键",
"settings.option.general.keybindings.pressCombination":"按下两个键组合来更新操作设定。",
"settings.option.general.keybindings.library": "资料库",
"settings.option.general.keybindings.session": "聆听",
"settings.option.general.keybindings.control": "控制",
"settings.option.general.keybindings.interface": "界面",
"settings.option.general.keybindings.advanced": "高级",
"settings.option.general.keybindings.pressCombination": "按下两个键组合来更新操作设定。",
"settings.option.general.keybindings.pressEscape": "按下 Esc 键返回。",
"settings.notyf.general.keybindings.update.success":"快捷键更新成功。",
"settings.prompt.general.keybindings.update.success":"快捷键更新成功,按下 OK 重新启动 Cider.",
"settings.option.general.keybindings.open": "打开",
"settings.option.general.themeUpdateNotification":"自动检查主题更新",
"settings.option.general.showLovedTracksInline":"行内显示喜爱曲目",
"settings.description.search":"搜索",
"settings.description.albums":"资料库专辑",
"settings.description.artists":"资料库艺人",
"settings.description.browse":"浏览",
"settings.description.private":"隐身聆听",
"settings.description.remote":"远程控制",
"settings.description.audio":"音频设定",
"settings.description.plugins":"插件目录",
"settings.description.cast":"投射到装置",
"settings.description.settings":"设置",
"settings.description.developer":"开发者",
"settings.description.listnow":"现在就听",
"settings.description.recentAdd":"最近加入",
"settings.description.songs":"歌曲",
"settings.notyf.general.keybindings.update.success": "快捷键更新成功。",
"settings.prompt.general.keybindings.update.success": "快捷键更新成功,按下 OK 重新启动 Cider。",
"settings.option.general.themeUpdateNotification": "自动检查主题更新",
"settings.option.general.showLovedTracksInline": "行内显示喜爱曲目",
"settings.description.search": "搜索",
"settings.description.albums": "资料库专辑",
"settings.description.artists": "资料库艺人",
"settings.description.browse": "浏览",
"settings.description.private": "隐身聆听",
"settings.description.remote": "远程控制",
"settings.description.audio": "音频设定",
"settings.description.plugins": "插件目录",
"settings.description.cast": "投射到装置",
"settings.description.settings": "设置",
"settings.description.developer": "开发者",
"settings.description.listnow": "现在就听",
"settings.description.recentAdd": "最近加入",
"settings.description.songs": "歌曲",
"settings.notyf.updateCider.update-not-available": "没有可用的更新",
"settings.notyf.updateCider.update-downloaded": "更新已成功下载,重启后进行更新",
"settings.notyf.updateCider.update-timeout": "更新超时",
"settings.header.audio": "音频",
"settings.header.audio.description": "调整 Cider 的音频设置",
"settings.option.audio.advanced":"高级功能",
"settings.option.audio.changePlaybackRate":"修改播放速度",
"settings.option.audio.playbackRate":"播放速度",
"settings.option.audio.playbackRate.change":"修改",
"settings.option.audio.volumeStep": "音量改变量",
"settings.option.audio.advanced": "高级功能",
"settings.option.audio.maxVolume": "最大音量",
"settings.option.audio.changePlaybackRate": "修改播放速度",
"settings.option.audio.playbackRate": "播放速度",
"settings.option.audio.playbackRate.change": "修改",
"settings.option.audio.quality": "音质",
"settings.header.audio.quality.hireslossless": "高解析度无损",
"settings.header.audio.quality.hireslossless.description": "(最高 24 位/192 kHz)",
"settings.header.audio.quality.lossless": "无损",
"settings.header.audio.quality.lossless.description": "(最高 24 位/48 kHz)",
"settings.header.audio.quality.high": "高音质",
"settings.header.audio.quality.high.description":"256 kbps",
"settings.header.audio.quality.high.description": "256 kbps",
"settings.header.audio.quality.standard": "高效率",
"settings.header.audio.quality.standard.description":"64 kbps",
"settings.header.audio.quality.standard.description": "64 kbps",
"settings.option.audio.seamlessTransition": "无缝播放",
"settings.option.audio.enableAdvancedFunctionality": "高级音频功能",
"settings.option.audio.enableAdvancedFunctionality.description": "打开 AudioContext 将启用类似音量平衡和等化器的高级设置。但这并不一定适合每部电脑,可能会发生音乐卡顿。",
"settings.warn.audio.enableAdvancedFunctionality.lowcores":"您的电脑可能无法处理这些功能, 您确定要继续?",
"settings.warn.audio.enableAdvancedFunctionality.lowcores": "您的电脑可能无法处理这些功能, 您确定要继续?",
"settings.option.audio.audioLab": "Cider 音频实验室",
"settings.option.audio.audioLab.description": "包含由 Cider 开发团队进行的各种音频优化功能。",
"settings.option.audio.audioLab.subheader":"Designed by Cider Acoustic Technologies in California",
"settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California",
"settings.warn.audioLab.withoutAF": "使用 Cider 音频实验室需要打开进阶音频功能才可使用。",
"settings.warn.enableAdvancedFunctionality":"此功能需要开启高级音频功能才可使用。",
"settings.warn.enableAdvancedFunctionality": "此功能需要开启高级音频功能才可使用。",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "模拟温暖",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "以 Korg Nutube 6P1 为蓝本的模拟温暖。",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "模拟温暖强度",
@ -401,18 +404,20 @@
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.E68_2": "宇治抹茶奶茶",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.E168_1": "春毫茉莉玛琪雅朵",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z3600": "北海道奶茶",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500": "月光软饼干",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.BSCBM":"布蕾黑糖鲜奶",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.CUDDLE":"温暖抱抱",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500A": "月光软饼干",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.BSCBM": "布蕾黑糖鲜奶",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500B": "樱桃克拉芙缇",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.Z8500C": "宇治抹茶麻糬",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.CUDDLE": "温暖抱抱",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider 数码增强音频处理™️",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "通过人类的听力心理学模型和 AAC 编码特色的即时算法,强化 AAC 音频的感知音频质量。",
"settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "数码增强音频处理与空间音频不兼容,请先停用空间音频。",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "数码增强音频处理设置",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "将更改音频处理的激进/振奋程度(增强选项有可能会引起杂讯)。",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "标准",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.adaptive":"自适应",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.legacy":"传统",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.adaptive": "自适应",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.legacy": "传统",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "增强",
"settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility":"数码增强音频处理与空间音频不兼容,请先停用空间音频。",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "音量平衡",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "自动将歌曲播放音量调整到相同水平,享受更舒适的聆听体验。",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.disabled": "此功能由音频实验室管理",
@ -421,28 +426,25 @@
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile": "Cider 音频空间配置档",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.description": "变更音频空间的配置档,需重新启动应用程序。",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.standard": "标准",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.soundstage":"声场",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.separation":"分离感",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.minimal":"微调",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.soundstage": "声场",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.separation": "分离感",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.minimal": "微调",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.audiophile": "发烧友",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.diffused": "扩散",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.bplk": "安可",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.hw2k": "延长版安可",
"settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "音频空间无法与 CAP 相容,请关闭 CAP 在进行操作。",
"settings.option.audio.dbspl.display":"显示 dB SPL(声压)",
"settings.option.audio.dbspl.description":"(专业用户选项) 音量滑动条显示 dB SPL 而非 dBFS.",
"settings.option.audio.dbfs.calibration":"0 dBFS 校正",
"settings.option.audio.dbfs.description":"Enter the peak Z-weighted dB SPL when Cider is at 0 dBFS.",
"settings.option.visual.uiscale": "UI界面大小",
"settings.option.audio.dbspl.display": "显示 dB SPL(声压)",
"settings.option.audio.dbspl.description": "(专业用户选项) 音量滑动条显示 dB SPL 而非 dBFS。",
"settings.option.audio.dbfs.calibration": "0 dBFS 校正",
"settings.option.audio.dbfs.description": "输入当 Cider 为 0 dBFS 时的峰值 Z 加权 dB SPL。",
"settings.header.visual": "外观",
"settings.header.visual.description": "调整 Cider 的外观",
"settings.option.visual.windowStyle":"窗口风格",
"settings.option.visual.customAccentColor": "自定义强调色",
"settings.option.visual.accentColor": "强调色",
"settings.option.visual.purplePodcastPlaybackBar": "播放播客时使用紫色进度条",
"settings.option.visual.windowColor": "窗口色调",
"settings.option.visual.windowStyle": "窗口风格",
"settings.option.visual.windowBackgroundStyle": "窗口背景样式",
"settings.header.visual.windowBackgroundStyle.none": "无",
"settings.header.visual.windowBackgroundStyle.artwork": "专辑插图",
"settings.header.visual.windowBackgroundStyle.image": "图像",
"settings.header.visual.windowBackgroundStyle.color":"色调",
"settings.option.visual.animatedArtwork": "动态专辑插图",
"settings.header.visual.animatedArtwork.always": "总是显示",
"settings.header.visual.animatedArtwork.limited": "只在艺人页面和专辑插图显示",
@ -458,20 +460,22 @@
"settings.option.visual.hardwareAcceleration.description": "需要重启 Cider 才会生效",
"settings.header.visual.hardwareAcceleration.default": "默认",
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
"settings.option.visual.uiscale": "UI界面大小",
"settings.header.visual.theme": "主题",
"settings.option.visual.theme.github.download": "从 GitHub 链接安装",
"settings.option.visual.theme.github.openfolder":"开启主题文件夹",
"settings.option.visual.theme.github.openfolder": "开启主题文件夹",
"settings.option.visual.theme.github.explore": "浏览 GitHub 上的主题",
"settings.header.visual.theme.github.page":"GitHub 上的主题",
"settings.option.visual.theme.github.install.confirm":"你确定要安装 {{ repo }}",
"settings.header.visual.theme.github.page": "GitHub 上的主题",
"settings.option.visual.theme.github.install.confirm": "你确定要安装 {{ repo }}",
"settings.prompt.visual.theme.github.URL": "输入您要安装的窗口主题链接",
"settings.prompt.visual.theme.uninstallTheme":"你确定要删除 {{ theme }}",
"settings.option.visual.theme.checkForUpdates":"检查更新",
"settings.option.visual.theme.manageStyles":"管理风格",
"settings.option.visual.theme.uninstall":"卸载",
"settings.option.visual.theme.viewInfo":"查看信息",
"settings.option.visual.theme.github.available":"可使用的主题",
"settings.option.visual.theme.github.applied":"已应用",
"settings.prompt.visual.theme.uninstallTheme": "你确定要删除 {{ theme }}",
"settings.option.visual.theme.checkForUpdates": "检查更新",
"settings.header.visual.styles": "主题",
"settings.option.visual.theme.manageStyles": "管理主题",
"settings.option.visual.theme.uninstall": "卸载",
"settings.option.visual.theme.viewInfo": "查看信息",
"settings.option.visual.theme.github.available": "可使用的主题",
"settings.option.visual.theme.github.applied": "已应用",
"settings.notyf.visual.theme.install.success": "主题成功安装",
"settings.notyf.visual.theme.install.error": "主题安装失败",
"settings.header.visual.plugin": "插件",
@ -503,21 +507,27 @@
"settings.option.lyrics.enableQQLyrics": "启用 QQ 音乐的歌词",
"settings.header.connectivity": "外部连接",
"settings.header.connectivity.description": "调整 Cider 与外部应用的交互设置",
"settings.option.connectivity.discordRPC": "Discord 动态",
"settings.option.connectivity.playbackNotifications": "歌曲播放通知",
"settings.option.connectivity.discordRPC": "Discord 动态",
"settings.option.connectivity.discordRPC.clientName": "应用程序名称",
"settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态",
"settings.option.connectivity.discordRPC.hideButtons": "隐藏 Discord 动态上的按钮",
"settings.option.connectivity.discordRPC.hideTimestamp":"隐藏 Discord 动态上的时间戳",
"settings.option.connectivity.discordRPC.hideTimestamp": "隐藏 Discord 动态上的时间戳",
"settings.option.connectivity.discordRPC.detailsFormat": "详细信息格式",
"settings.option.connectivity.discordRPC.stateFormat": "动态格式",
"settings.option.connectivity.discordRPC.reload":"重新加载 DiscordRPC",
"settings.option.connectivity.discordRPC.reconnectedToUser":"DiscordRPC 重新连接至用户: {{user}} ({{userid}})",
"settings.option.connectivity.discordRPC.reload": "重新加载 DiscordRPC",
"settings.option.connectivity.discordRPC.reconnectedToUser": "DiscordRPC 重新连接至用户: {{user}} ({{userid}})",
"settings.option.connectivity.lastfmScrobble": "Last.FM 音乐记录",
"settings.option.connectivity.lastfmScrobble.delay": "Last.FM 歌曲追踪延迟 (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "打开 Last.FM 正在聆听",
"settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除合作者 (Last.FM)",
"settings.option.connectivity.lastfmScrobble.filterLoop": "不记录单曲循环 (Last.FM)",
"settings.option.connectivity.lastfmScrobble.filterLoop.description": "防止循环单曲被记录或展示在Last.FM 的正在播放列表中。",
"settings.option.connectivity.lastfmScrobble.filterTypes": "过滤媒体类型 (Last.fm)",
"settings.option.connectivity.lastfmScrobble.manualToken": "手动输入 Last.fm 验证码",
"settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm 连接超时",
"settings.notyf.connectivity.lastfmScrobble.connectSuccess": "Last.fm 连接成功",
"settings.notyf.connectivity.lastfmScrobble.connecting": "正在连接至 Last.fm...",
"settings.header.debug": "Debug",
"settings.option.debug.copy_log": "拷贝日志至剪贴板",
"settings.option.debug.openAppData": "打开 Cider 程序文件夹",
@ -529,15 +539,21 @@
"settings.option.experimental.unknownPlugin.description": "允许从 Cider 来源以外的 repo 安装插件",
"settings.option.experimental.compactUI": "紧凑型 UI",
"settings.option.window.close_button_hide": "关闭按钮将 Cider 隐藏至系统栏",
"settings.option.window.maxElementScale": "最大元素比例",
"settings.option.experimental.inline_playlists": "将播放列表做为行内元素显示",
"settings.option.advanced.playlistTrackMapping": "播放列表追踪映射",
"settings.option.advanced.playlistTrackMapping.description": "打开对播放列表的深度扫描,以确认歌曲在哪些播放列表中。但播放列表加载时间会显著增加。",
"settings.option.visual.transparent": "透明窗口框架",
"settings.option.visual.transparent.description": "需主题有支持透明框架,且须重新启动才会生效。",
"settings.option.visual.customAccentColor": "自定义强调色",
"settings.option.visual.accentColor": "强调色",
"settings.option.visual.purplePodcastPlaybackBar": "播放播客时使用紫色进度条",
"settings.option.visual.windowColor": "窗口色调",
"settings.header.visual.windowBackgroundStyle.color": "色调",
"settings.header.advanced": "高级",
"settings.header.connect":"同步",
"settings.option.connect.link_account":"开启 Cider Connect 同步",
"settings.option.connect.link_account.description":"将您的 Discord 帐户与 Cider Connect 关联后,您可以储存用户资料,包括设定、均衡器,并在后续版本中加入更多可同步选项。(正在更新中)",
"settings.header.connect": "同步",
"settings.option.connect.link_account": "开启 Cider Connect 同步",
"settings.option.connect.link_account.description": "将您的 Discord 帐户与 Cider Connect 关联后,您可以储存用户资料,包括设定、均衡器,并在后续版本中加入更多可同步选项。(正在更新中)",
"spatial.notTurnedOn": "请在设置中开启空间音频。",
"spatial.spatialProperties": "空间属性",
"spatial.width": "宽度",
@ -560,54 +576,54 @@
"settings.header.unfinished": "未完成",
"remote.web.title": "Cider 远程控制",
"remote.web.description": "扫描以下的二维码以控制 Cider",
"share.platform.twitter.tweet": "在 Apple Music 上聆听 {{song}}。 \n\n{{url}}\n\n#AppleMusic #Cider",
"share.platform.twitter": "Twitter",
"share.platform.facebook": "Facebook",
"share.platform.reddit": "Reddit",
"share.platform.telegram": "Telegram",
"share.platform.whatsapp": "WhatsApp",
"share.platform.messenger": "Messenger",
"share.platform.email": "电子邮件",
"share.platform.songLink": "复制 song.link 链接",
"share.platform.clipboard": "复制到剪贴板",
"about.thanks": "郑重感谢 Cider Collective 以及为这个项目提供支持的贡献者。",
"share.platform.twitter.tweet":"在 Apple Music 上聆听 {{song}}。 \n\n{{url}}\n\n#AppleMusic #Cider",
"share.platform.twitter":"Twitter",
"share.platform.facebook":"Facebook",
"share.platform.reddit":"Reddit",
"share.platform.telegram":"Telegram",
"share.platform.whatsapp":"WhatsApp",
"share.platform.messenger":"Messenger",
"share.platform.email":"电子邮件",
"share.platform.songLink":"复制 song.link 链接",
"share.platform.clipboard":"复制到剪贴板",
"oobe.yes":"好的",
"oobe.no":"不",
"oobe.next":"下一步",
"oobe.previous":"上一步",
"oobe.done":"完成",
"oobe.amupsell.title":"在我们开始之前",
"oobe.amupsell.text":"使用 Cider 需要付费的 Apple Music 订阅。\nCider 不能在 Apple Music Voice 计划或某些促销试用订阅状态下使用。 如果您已经订阅 Apple Music请点击下一步继续。",
"oobe.amupsell.subscribeBtn":"订阅 Apple Music",
"oobe.amupsell.explainBtn":"这是什么?",
"oobe.amupsell.subscribeUrl":"https://apple.co/3MdqJVQ",
"oobe.amupsell.amWebUrl":"https://beta.music.apple.com/",
"oobe.amupsell.promoExplained":"Cider 无法获取部分促销活动与非美区 Apple Muisc 试用状态下的网络播放器API. 要验证您的试用订阅是否能够在Cider内使用, 点击<a href='{{ amWebUrl }}'>{{ amWebUrl }}</a>, 登陆后尝试播放音乐。如果能够播放,您就可以使用 Cider 了!否则请考虑订阅 Apple Music 服务: <a href='{{ subscribeUrl }}'>{{ subscribeUrl }}</a>。",
"oobe.intro.title":"欢迎使用 Cider",
"oobe.intro.subtitle":"",
"oobe.intro.text":"为了按您喜欢的方式使用 Cider ,请先完成一些设置。您之后可以随时改变这些设置。",
"oobe.general.title":"通用设置",
"oobe.general.subtitle":"",
"oobe.general.text":"",
"oobe.audio.title":"音频设置",
"oobe.audio.subtitle":"",
"oobe.audio.text":"Cider 能够自定义调整和设置的音频属性提供丰富的高品质音频体验包括Cider Adrenaline Processor气氛实现器和空间音频。要启用这些功能必须启用 \"高级音频功能\"。",
"oobe.audio.advancedFunctionality":"",
"oobe.visual.title":"外观设置",
"oobe.visual.subtitle":"",
"oobe.visual.text":"",
"oobe.visual.layout.text":"Cider 拥有两种不同的窗口布局。Maverick 是一个类似 iTunes 的布局播放器在窗口的顶部。Mojave 是由 Cider 团队设计的一种新的布局。您可以在设置中随时改变布局。",
"oobe.visual.suggestingThemes":"主题能够个性化您的播放器。以下是推荐的几个主题:",
"oobe.visual.suggestingThemes.subtext":"(主题会从 GitHub 上下载)",
"oobe.visual.suggestingThemes.default":"Cider",
"oobe.visual.suggestingThemes.default.text":"传统的 Cider 主题。",
"oobe.visual.suggestingThemes.dark":"Dark",
"oobe.visual.suggestingThemes.dark.text":"暗黑模式。",
"oobe.visual.suggestingThemes.community1":"Groovy",
"oobe.visual.suggestingThemes.community1.text":"类 WinUI 主题。",
"oobe.visual.suggestingThemes.community2":"iTheme",
"oobe.visual.suggestingThemes.community2.text":"基于 MacOS Monterey 的 Apple Music bata 主题。",
"oobe.visual.suggestingThemes.community3":"Dracula",
"oobe.visual.suggestingThemes.community3.text":"著名的德古拉吸血鬼主题。",
"oobe.yes": "好的",
"oobe.no": "不",
"oobe.next": "下一步",
"oobe.previous": "上一步",
"oobe.done": "完成",
"oobe.amupsell.title": "在我们开始之前",
"oobe.amupsell.text": "使用 Cider 需要付费的 Apple Music 订阅。\nCider 不能在 Apple Music Voice 计划或某些促销试用订阅状态下使用。 如果您已经订阅 Apple Music请点击下一步继续。",
"oobe.amupsell.subscribeBtn": "订阅 Apple Music",
"oobe.amupsell.explainBtn": "这是什么?",
"oobe.amupsell.subscribeUrl": "https://apple.co/3MdqJVQ",
"oobe.amupsell.amWebUrl": "https://beta.music.apple.com/",
"oobe.amupsell.promoExplained": "Cider 无法获取部分促销活动与非美区 Apple Muisc 试用状态下的网络播放器API. 要验证您的试用订阅是否能够在Cider内使用, 点击<a href='{{ amWebUrl }}'>{{ amWebUrl }}</a>, 登陆后尝试播放音乐。如果能够播放,您就可以使用 Cider 了!否则请考虑订阅 Apple Music 服务: <a href='{{ subscribeUrl }}'>{{ subscribeUrl }}</a>。",
"oobe.intro.title": "欢迎使用 Cider",
"oobe.intro.subtitle": "",
"oobe.intro.text": "为了按您喜欢的方式使用 Cider ,请先完成一些设置。您之后可以随时改变这些设置。",
"oobe.general.title": "通用设置",
"oobe.general.subtitle": "",
"oobe.general.text": "",
"oobe.audio.title": "音频设置",
"oobe.audio.subtitle": "",
"oobe.audio.text": "Cider 能够自定义调整和设置的音频属性提供丰富的高品质音频体验包括Cider Adrenaline Processor气氛实现器和空间音频。要启用这些功能必须启用 \"高级音频功能\"。",
"oobe.audio.advancedFunctionality": "",
"oobe.visual.title": "外观设置",
"oobe.visual.subtitle": "",
"oobe.visual.text": "",
"oobe.visual.layout.text": "Cider 拥有两种不同的窗口布局。Maverick 是一个类似 iTunes 的布局播放器在窗口的顶部。Mojave 是由 Cider 团队设计的一种新的布局。您可以在设置中随时改变布局。",
"oobe.visual.suggestingThemes": "主题能够个性化您的播放器。以下是推荐的几个主题:",
"oobe.visual.suggestingThemes.subtext": "(主题会从 GitHub 上下载)",
"oobe.visual.suggestingThemes.default": "Cider",
"oobe.visual.suggestingThemes.default.text": "经典的 Cider 主题。",
"oobe.visual.suggestingThemes.dark": "Dark",
"oobe.visual.suggestingThemes.dark.text": "暗黑模式。",
"oobe.visual.suggestingThemes.community1": "Groovy",
"oobe.visual.suggestingThemes.community1.text": "类 WinUI 主题。",
"oobe.visual.suggestingThemes.community2": "iTheme",
"oobe.visual.suggestingThemes.community2.text": "经典的苹果风主题。",
"oobe.visual.suggestingThemes.community3": "Dracula",
"oobe.visual.suggestingThemes.community3.text": "著名的德古拉吸血鬼主题。",
"oobe.amsignin.title": ""
}

View file

@ -135,6 +135,7 @@
"term.videos": "音樂錄影帶",
"term.menu": "選單",
"term.check": "檢查",
"term.themeManaged": "此功能現在由主題管理。",
"term.aboutArtist": "關於{{artistName}}",
"term.requestError": "請求發生錯誤。",
"term.song.link.generate": "正在取得 song.link 的分享網址...",
@ -142,8 +143,10 @@
"term.version": "版本",
"term.creditDesignedBy": "由 ${authorUsername} 設計",
"term.plugin": "模組",
"term.plugins": "模組",
"term.pluginMenu": "模組選單",
"term.pluginMenu.none": "沒有交互式模組",
"term.fullscreen" : "全螢幕模式",
"home.title": "首頁",
"home.recentlyPlayed": "最近播放",
"home.recentlyAdded": "最近加入",
@ -232,6 +235,7 @@
"action.cast.scanning": "尋找中...",
"action.createNew": "新增...",
"action.refresh": "重新整理",
"menubar.options.reload": "重新載入",
"settings.header.general": "一般",
"settings.header.general.description": "調整 Cider 的一般設定",
"settings.option.general.resumebehavior": "還原行為",
@ -345,6 +349,7 @@
"settings.option.visual.theme.github.explore": "探索 GitHub 上的主題",
"settings.prompt.visual.theme.github.URL": "輸入你要安裝的主題網址",
"settings.option.visual.theme.checkForUpdates": "檢查更新",
"settings.header.visual.styles": "主題",
"settings.option.visual.theme.manageStyles": "管理主題",
"settings.option.visual.theme.uninstall": "移除",
"settings.option.visual.theme.viewInfo": "查看資訊",
@ -366,6 +371,7 @@
"settings.option.visual.showPersonalInfo": "顯示個人檔案",
"settings.header.window": "視窗",
"settings.header.window.description": "調整 Cider 的視窗設定",
"settings.option.window.maxElementScale": "最大元素比例",
"settings.option.window.openOnStartup": "開機時,啟動 Cider ",
"settings.option.window.openOnStartup.hidden": "啟動時,自動隱藏至系統列",
"settings.option.window.useNativeTitleBar": "使用原生視窗標題列",

View file

@ -64,7 +64,7 @@ export class BrowserWindow {
"pages/groupings",
"pages/charts",
"pages/settings",
"pages/installed-themes",
//"pages/installed-themes",
"pages/listen_now",
"pages/radio",
"pages/home",
@ -80,13 +80,12 @@ export class BrowserWindow {
"pages/about",
"pages/library-videos",
"pages/remote-pair",
"pages/themes-github",
"pages/plugins-github",
//"pages/themes-github",
//"pages/plugins-github",
"pages/replay",
"pages/audiolabs",
"pages/zoo",
"pages/plugin-renderer",
"pages/keybinds",
"pages/oobe",
"components/app-content",
"components/sidebar",
@ -126,7 +125,11 @@ export class BrowserWindow {
"components/hello-world",
"components/inline-collection-list",
"components/settings-window",
"components/pagination"
"components/pagination",
"components/settings-keybinds",
"components/settings-themes",
"components/settings-themes-github",
"components/settings-plugins-github",
],
appRoutes: [
{
@ -276,6 +279,10 @@ export class BrowserWindow {
page: "replay",
component: `<replay-page></replay-page>`,
condition: `$root.page == 'replay'`
}, {
page: "keydinds",
component: `<keybinds-settings></keybinds-settings>`,
condition: `$root.page == 'keybinds-settings'`
}
]
},
@ -1563,4 +1570,4 @@ export class BrowserWindow {
server2.start();
console.log('remote broadcasted')
}
}
}

View file

@ -244,12 +244,13 @@ export class Store {
"windowColor": "#000000",
"customAccentColor": false,
"accentColor": "#fc3c44",
"purplePodcastPlaybackBar": false
"purplePodcastPlaybackBar": false,
"maxElementScale": -1 // -1 default, anything else is a custom scale
},
"lyrics": {
"enable_mxm": false,
"enable_mxm": true,
"mxm_karaoke": false,
"mxm_language": "en",
"mxm_language": "disabled",
"enable_qq": false,
"enable_yt": false,
},
@ -258,7 +259,7 @@ export class Store {
"experiments": [],
"playlistTrackMapping": true,
"ffmpegLocation": "",
"disableLogging": false
"disableLogging": true
},
"connectUser": {
"auth": null,

View file

@ -52,22 +52,50 @@ export default class DiscordRPC {
const self = this
this.connect();
console.debug(`[Plugin][${this.name}] Ready.`);
ipcMain.on('updateRPCImage', (_event, imageurl) => {
ipcMain.on('updateRPCImage', async (_event, imageurl) => {
if (!this._utils.getStoreValue("general.privateEnabled")) {
fetch('https://api.cider.sh/v1/images', {
let b64data = ""
let postbody = ""
if (imageurl.startsWith("/ciderlocalart")){
let port = await _win.webContents.executeJavaScript(
`app.clientPort`
);
console.log("http://localhost:"+port+imageurl)
const response = await fetch("http://localhost:"+port+imageurl)
b64data = (await response.buffer()).toString('base64');
postbody = JSON.stringify({data: b64data})
fetch('https://api.cider.sh/v1/images', {
method: 'POST',
body: JSON.stringify({url: imageurl}),
headers: {
'Content-Type': 'application/json',
'User-Agent': _win.webContents.getUserAgent()
},
})
.then(res => res.json())
.then(function (json) {
self._attributes["artwork"]["url"] = json.url
self.setActivity(self._attributes)
method: 'POST',
body: postbody,
headers: {
'Content-Type': 'application/json',
'User-Agent': _win.webContents.getUserAgent()
},
})
.then(res => res.json())
.then(function (json) {
self._attributes["artwork"]["url"] = json.url
self.setActivity(self._attributes)
})
} else {
postbody = JSON.stringify({url: imageurl})
fetch('https://api.cider.sh/v1/images', {
method: 'POST',
body: postbody,
headers: {
'Content-Type': 'application/json',
'User-Agent': _win.webContents.getUserAgent()
},
})
.then(res => res.json())
.then(function (json) {
self._attributes["artwork"]["url"] = json.url
self.setActivity(self._attributes)
})
}
}
})
ipcMain.on("reloadRPC", () => {
@ -88,6 +116,7 @@ export default class DiscordRPC {
})
}
/**
* Runs on app stop
*/

View file

@ -7,10 +7,7 @@ export default class lastfm {
public version: string = '2.0.0';
public author: string = 'Core (Cider Collective)';
/**
* Private variables for interaction in plugins
*/
private _attributes: any;
private _apiCredentials = {
key: "f9986d12aab5a0fe66193c559435ede3",
secret: "acba3c29bd5973efa38cc2f0b63cc625"
@ -31,31 +28,36 @@ export default class lastfm {
constructor(utils: any) {
this._utils = utils;
this.initializeLastFM("", this._apiCredentials)
}
onReady(_win: Electron.BrowserWindow): void {
this.initializeLastFM("", this._apiCredentials)
// Register the ipcMain handlers
this._utils.getIPCMain().handle('lastfm:url', (event: any) => {
console.debug(`${lastfm.name}:url`)
console.debug(`[${lastfm.name}:url] Called.`)
return this._lfm.getAuthenticationUrl({"cb": "cider://auth/lastfm"})
})
this._utils.getIPCMain().on('lastfm:auth', (event: any, token: string) => {
console.debug(`${lastfm.name}:auth`, token)
console.debug(`[${lastfm.name}:auth] Token: `, token)
this.authenticateLastFM(token)
})
this._utils.getIPCMain().on('lastfm:disconnect', (_event: any) => {
this._lfm.setSessionCredentials(null, null);
this._authenticated = false;
console.debug(`${lastfm.name}:disconnect`)
console.debug(`[${lastfm.name}:disconnect] Disconnected`)
})
this._utils.getIPCMain().on('lastfm:nowPlayingChange', (event: any, attributes: any) => {
if (this._utils.getStoreValue("connectivity.lastfm.filter_loop")) return;
this.onNowPlayingItemDidChange(attributes)
if (this._utils.getStoreValue("connectivity.lastfm.filter_loop") || this._utils.getStoreValue("general.privateEnabled")) return;
this.updateNowPlayingTrack(attributes)
})
this._utils.getIPCMain().on('lastfm:scrobbleTrack', (event: any, attributes: any) => {
if (this._utils.getStoreValue("general.privateEnabled")) return;
this.scrobbleTrack(attributes)
})
}
@ -64,22 +66,15 @@ export default class lastfm {
* @param attributes Music Attributes (attributes.status = current state)
*/
onPlaybackStateDidChange(attributes: object): void {
this._attributes = attributes
// this.scrobbleTrack(attributes)
}
/**
* Runs on song change
* @param attributes Music Attributes
* @param scrobble
*/
onNowPlayingItemDidChange(attributes: any): void {
onNowPlayingItemDidChange(attributes: any, scrobble = false): void {
if (this._utils.getStoreValue("general.privateEnabled")) return;
this._attributes = attributes
if (!attributes?.lfmTrack || !attributes?.lfmAlbum) {
this.verifyTrack(attributes)
return
}
this.scrobbleTrack(attributes)
this.updateNowPlayingTrack(attributes)
}
@ -90,6 +85,7 @@ export default class lastfm {
* @private
*/
private initializeLastFM(token: string, api: { key: string, secret: string }): void {
console.debug(`[${lastfm.name}:initialize] Initializing LastFM`)
const LastfmAPI = require("lastfmapi")
this._lfm = new LastfmAPI({
'api_key': api.key,
@ -113,7 +109,7 @@ export default class lastfm {
if (!token) return;
this._lfm.authenticate(token, (err: any, session: any) => {
if (err) {
console.error(err);
console.error(`[${lastfm.name}:authenticate] Error: ${typeof err === "string" ? err : err.message}`);
this._utils.getWindow().webContents.executeJavaScript(`app.notyf.error("${err.message}");`)
return;
@ -127,37 +123,36 @@ export default class lastfm {
/**
* Verifies the track information with lastfm
* @param attributes
* @param callback
* @private
*/
private verifyTrack(attributes: any): object {
private verifyTrack(attributes: any, callback: Function): void {
if (!attributes) return attributes;
if (!attributes.lfmAlbum) {
return this._lfm.album.getInfo({
this._lfm.album.getInfo({
"artist": attributes.artistName,
"album": attributes.albumName
}, (err: any, data: any) => {
if (err) {
console.error(`[${lastfm.name}] [album.getInfo] Error: ${typeof err === "string" ? err : err.message}`)
console.error(err)
return {};
}
if (data) {
attributes.lfmAlbum = data
callback(attributes)
}
this.onNowPlayingItemDidChange(attributes)
})
} else {
return this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => {
this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => {
if (err) {
console.error(`[${lastfm.name}] [track.getCorrection] Error: ${typeof err === "string" ? err : err.message}`)
console.error(err)
return {};
}
if (data) {
attributes.lfmTrack = data.correction.track
callback(attributes)
}
this.onNowPlayingItemDidChange(attributes)
})
}
@ -170,44 +165,53 @@ export default class lastfm {
* @private
*/
private scrobbleTrack(attributes: any): void {
if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._scrobbleCache.track === attributes.lfmTrack.name)) return;
if (this._scrobbleDelay) {
clearTimeout(this._scrobbleDelay);
if (!attributes?.lfmTrack || !attributes?.lfmAlbum) {
this.verifyTrack(attributes, (a: any) => {
this.scrobbleTrack(a)
})
return
}
// Scrobble delay
this._scrobbleDelay = setTimeout(() => {
if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._scrobbleCache.track === attributes.lfmTrack.name)) return;
// Scrobble
const scrobble = {
'artist': attributes.lfmTrack.artist.name,
'track': attributes.lfmTrack.name,
'album': attributes.lfmAlbum.name,
'albumArtist': attributes.lfmAlbum.artist,
'timestamp': new Date().getTime() / 1000,
'trackNumber': attributes.trackNumber,
'duration': attributes.durationInMillis / 1000,
// Scrobble
const scrobble = {
'artist': attributes.lfmTrack.artist.name,
'track': attributes.lfmTrack.name,
'album': attributes.lfmAlbum.name,
'albumArtist': attributes.lfmAlbum.artist,
'timestamp': new Date().getTime() / 1000,
'trackNumber': attributes.trackNumber,
'duration': attributes.durationInMillis / 1000,
}
// Easy Debugging
console.debug(`[${lastfm.name}:scrobble] Scrobbling ${scrobble.artist} - ${scrobble.track}`)
// Scrobble the track
this._lfm.track.scrobble(scrobble, (err: any, _res: any) => {
if (err) {
console.error(`[${lastfm.name}:scrobble] Scrobble failed: ${err.message}`);
} else {
console.debug(`[${lastfm.name}:scrobble] Track scrobbled: ${scrobble.artist} - ${scrobble.track}`);
this._scrobbleCache = scrobble
}
// Easy Debugging
if (!this._utils.getApp().isPackaged) {
console.debug(scrobble)
}
// Scrobble the track
this._lfm.track.scrobble(scrobble, (err: any, _res: any) => {
if (err) {
console.error(`[${lastfm.name}:scrobble] Scrobble failed: ${err.message}`);
} else {
console.debug(`[${lastfm.name}:scrobble] Track scrobbled: ${scrobble.artist} - ${scrobble.track}`);
this._scrobbleCache = scrobble
}
});
}, Math.round(attributes.durationInMillis * Math.min((this._utils.getStoreValue("connectivity.lastfm.scrobble_after") / 100), 0.8)))
});
}
/**
* Updates the now playing track
* @param attributes
* @private
*/
private updateNowPlayingTrack(attributes: any): void {
if (!attributes?.lfmTrack || !attributes?.lfmAlbum) {
this.verifyTrack(attributes, (a: any) => {
this.updateNowPlayingTrack(a)
})
return
}
if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._nowPlayingCache.track === attributes.lfmTrack.name)) return;
const nowPlaying = {
@ -223,7 +227,6 @@ export default class lastfm {
if (err) {
console.error(`[${lastfm.name}:updateNowPlaying] Now Playing Update failed: ${err.message}`);
} else {
console.log(res)
console.debug(`[${lastfm.name}:updateNowPlaying] Now Playing Updated: ${nowPlaying.artist} - ${nowPlaying.track}`);
this._nowPlayingCache = nowPlaying
}

View file

@ -6,8 +6,7 @@ import * as mm from 'music-metadata';
import {Md5} from 'ts-md5/dist/md5';
import e from "express";
import { EventEmitter } from 'events';
import { parseFile, recursiveFolderSearch } from 'cider_utils';
export class LocalFiles {
static localSongs: any = [];
@ -38,21 +37,20 @@ export class LocalFiles {
let folders = utils.getStoreValue("libraryPrefs.localPaths")
if (folders == null || folders.length == null || folders.length == 0) folders = []
console.log('folders', folders)
let files: any[] = []
let parseFileQueue: any[] = []; let mmQueue: any[] = []
for (var folder of folders) {
// get files from the Music folder
files = files.concat(await LocalFiles.getFiles(folder))
// Recursively search and add
let result = await recursiveFolderSearch(folder)
parseFileQueue = parseFileQueue.concat(result.parseFile)
mmQueue = mmQueue.concat(result.musicMetadata)
}
//console.log("cider.files", files2);
let supporttedformats = ["mp3", "aac", "webm", "flac", "m4a", "ogg", "wav", "opus"]
let audiofiles = files.filter(f => supporttedformats.includes(f.substring(f.lastIndexOf('.') + 1)));
// console.log("cider.files2", audiofiles, audiofiles.length);
if (parseFileQueue.length !== 0 || mmQueue.length !== 0) {console.log('Recursive Folder Search in Cider Utils worki')}
let metadatalist = []
let metadatalistart = []
let numid = 0;
for (var audio of audiofiles) {
// Music Metadata fallback
for (var audio of mmQueue) {
try {
const metadata = await mm.parseFile(audio);
let lochash = Md5.hashStr(audio) ?? numid;
@ -104,7 +102,7 @@ export class LocalFiles {
lossless: metadata.format?.lossless,
container: metadata.format?.container,
bitDepth: metadata.format?.bitsPerSample ?? 0,
sampleRate: metadata.format?.sampleRate ?? 0,
sampleRate: metadata.format?.sampleRate ?? 0,
},
};
let art = {
@ -121,7 +119,80 @@ export class LocalFiles {
if (this.localSongs.length === 0 && numid % 10 === 0) { // send updated chunks only if there is no previous database
this.eventEmitter.emit('newtracks', metadatalist)}
}
} catch (e) { }
} catch (e) {console.error("error:", e)}
}
// Cider-Utils supported formats.
for (var audio of parseFileQueue) {
try {
const metadata = await parseFile(audio);
let lochash = Md5.hashStr(audio) ?? numid;
if (metadata != null) {
let form = {
"id": "ciderlocal" + lochash,
"_id": "ciderlocal" + lochash,
"type": "podcast-episodes",
"href": audio,
"attributes": {
"artwork": {
"width": 3000,
"height": 3000,
"url": "/ciderlocalart/" + "ciderlocal" + lochash,
},
"topics": [],
"url": "",
"subscribable": true,
"mediaKind": "audio",
"genreNames": [
""
],
// "playParams": {
// "id": "ciderlocal" + numid,
// "kind": "podcast",
// "isLibrary": true,
// "reporting": false },
"trackNumber": metadata.track_number ?? 0,
"discNumber": metadata.disc_number ?? 0,
"name": metadata.title ?? audio.substring(audio.lastIndexOf('\\') + 1),
"albumName": metadata.album,
"artistName": metadata.artist,
"copyright": metadata.copyright ?? "",
"assetUrl": "file:///" + audio,
"contentAdvisory": "",
"releaseDateTime": `${metadata.year ?? '2022'}-05-13T00:23:00Z`,
"durationInMillis": metadata.duration_in_ms ?? 0,
"bitrate": metadata.bitrate ?? 0,
"offers": [
{
"kind": "get",
"type": "STDQ"
}
],
"contentRating": "clean"
},
flavor: metadata.bitrate,
localFilesMetadata: {
lossless: metadata.lossless,
container: metadata.container,
bitDepth: metadata.bit_depth,
sampleRate: metadata.sample_rate ?? 0,
},
};
let art = {
id: "ciderlocal" + lochash,
_id: "ciderlocalart" + lochash,
url: metadata.artwork != undefined ? metadata.artwork : "",
}
metadatalistart.push(art)
numid += 1;
ProviderDB.db.putIfNotExists(form)
ProviderDB.db.putIfNotExists(art)
metadatalist.push(form)
if (this.localSongs.length === 0 && numid % 10 === 0) { // send updated chunks only if there is no previous database
this.eventEmitter.emit('newtracks', metadatalist)}
}
} catch (e) {console.error("error:", e)}
}
this.localSongs = metadatalist;
this.localSongsArts = metadatalistart;
@ -173,7 +244,7 @@ export class LocalFiles {
// metadata.common.picture[0].data.toString('base64')
res.setHeader('Cache-Control', 'public, max-age=31536000');
res.setHeader('Expires', new Date(Date.now() + 31536000).toUTCString());
res.setHeader('Expires', new Date(Date.now() + 31536000000).toUTCString());
res.setHeader('Content-Type', 'image/jpeg');
let data =

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-package"><line x1="16.5" y1="9.4" x2="7.5" y2="4.21"></line><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>

After

Width:  |  Height:  |  Size: 517 B

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="24px"
height="24px"
viewBox="0 0 24 24"
version="1.1"
id="svg4"
sodipodi:docname="style-svgrepo-com.svg"
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs8" />
<sodipodi:namedview
id="namedview6"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="36.541667"
inkscape:cx="8.031927"
inkscape:cy="12.054732"
inkscape:window-width="1920"
inkscape:window-height="1044"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
d="M23.14.93l-.07-.07A2.926 2.926 0 0 0 20.98 0a2.886 2.886 0 0 0-2.08.86L8.858 10.9a3.04 3.04 0 0 0-.53.72 7.793 7.793 0 0 0-4.1 1.621c-.191.144-.36.316-.5.51a6.08 6.08 0 0 0-.98 1.961c-.25.69-.59 1.631-1.22 3-.42.91-.75 1.541-.98 1.981a3.092 3.092 0 0 0-.54 1.631c.014.206.08.406.19.58a2.64 2.64 0 0 0 2.23 1.07 10.462 10.462 0 0 0 8.161-3.371c.378-.44.692-.932.93-1.461a7.882 7.882 0 0 0 .69-3.361.142.142 0 0 1 .02-.04c.325-.144.62-.347.87-.6L23.14 5.1A2.888 2.888 0 0 0 24 3.021 2.927 2.927 0 0 0 23.14.93zM9.7 18.317c-.17.368-.388.711-.65 1.02a8.393 8.393 0 0 1-6.891 2.6c.05-.1.11-.21.17-.32.24-.46.58-1.11 1.02-2.061a39.058 39.058 0 0 0 1.28-3.151c.14-.491.355-.957.64-1.381.062-.08.133-.154.21-.22a5.221 5.221 0 0 1 2.59-1.14c.121.537.396 1.027.79 1.411l.07.07c.35.357.788.616 1.27.75a5.614 5.614 0 0 1-.499 2.422zM21.73 3.691L11.678 13.735a.947.947 0 0 1-.67.28.983.983 0 0 1-.67-.28l-.07-.07a.948.948 0 0 1 0-1.34L20.309 2.271c.18-.173.42-.27.671-.271a.937.937 0 0 1 .67.27l.08.08c.36.374.36.967 0 1.341z"
fill="#494c4e"
fill-rule="evenodd"
id="path2"
style="fill:#000000;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -1,57 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
fill="none"
height="391"
viewBox="0 0 391 391"
width="391"
version="1.1"
id="svg10"
sodipodi:docname="ko_fi.svg"
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs14" />
<sodipodi:namedview
id="namedview12"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="2.1202046"
inkscape:cx="111.07419"
inkscape:cy="196.67913"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
<path
d="M 31.247286,101.05669 H 327.24729 v 199 H 31.247286 Z"
fill="#fff"
id="path2"
style="display:inline;fill:none;fill-opacity:1;stroke:none;stroke-width:5;stroke-linecap:square;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke markers fill" />
<path
d="m 311.81693,84.320186 c 30.63288,8.509134 52.99975,29.903524 61.02265,58.348344 9.4816,34.1581 -0.12156,67.58684 -26.1352,89.83214 -13.97929,11.91279 -39.50669,20.7866 -60.29329,20.7866 h -9.23849 l -0.97247,8.75225 c -2.30962,23.58246 -13.85773,39.5067 -32.82095,44.97685 -3.52521,1.09404 -30.63288,1.45871 -97.24724,1.45871 l -92.38476,0.12156 -7.293543,-3.40365 c -11.66967,-5.47016 -20.543481,-15.438 -23.947134,-26.98611 -0.486236,-1.94495 -0.972473,-44.49062 -0.972473,-94.57295 0,-98.098154 0,-97.976594 6.321071,-100.529335 1.701827,-0.607795 59.077579,-1.094031 138.941879,-1.094031 133.10716,-0.121559 136.38926,-0.121559 145.01995,2.309622 z"
fill="#579fbf"
id="path4"
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:12.1559;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
sodipodi:nodetypes="cccscccccccsccc" />
<path
d="m 278.02351,168.19593 v 41.33008 h 10.6972 c 18.84165,0 30.38977,-6.44263 37.92643,-21.15127 4.01145,-8.0229 4.25456,-8.99537 4.25456,-21.27284 0,-11.66967 -0.36467,-13.49305 -3.40365,-19.81412 -3.64677,-7.53667 -10.45408,-14.10085 -18.47698,-17.99074 -4.01145,-1.94495 -7.53666,-2.43118 -17.99074,-2.43118 h -13.00682 z"
fill="#579fbf"
id="path6"
style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:12.1559;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" />
<path
d="m 173.34293,137.08897 c -8.87381,2.91742 -11.66966,4.49769 -18.59853,10.21096 l -5.71328,4.74081 -5.22704,-4.25457 c -17.26138,-14.10085 -42.54566,-15.68112 -56.768074,-3.52521 -7.050426,6.07795 -9.967357,12.52058 -10.696711,23.58245 -0.607795,9.84629 1.458709,19.20633 6.077467,28.2017 1.337149,2.6743 7.171984,9.72473 12.885259,15.80268 17.869179,18.59854 51.541039,49.47454 53.972219,49.47454 1.45871,0 14.70865,-12.27747 33.18562,-30.75445 27.83703,-27.71546 31.24068,-31.48379 34.76589,-39.02045 4.98392,-10.57564 6.07796,-22.8531 3.03898,-32.09159 -5.95639,-17.74762 -28.44482,-28.44482 -46.9218,-22.36687 z"
fill="#ff5f5f"
id="path8"
style="display:inline;stroke-width:1.21559" />
<svg width="38" height="38" viewBox="0 0 600 400" xmlns="http://www.w3.org/2000/svg">
<path style="fill:#fff;fill-opacity:1;fill-rule:nonzero;stroke:#000;stroke-width:13;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1" d="M464.7 222.884c-21.905 2.737-39.702.683-39.702.683V89.44h41.754s46.548 13 46.548 62.273c0 45.165-23.272 62.959-48.6 71.171m115.382-94.16C561.821 32.277 465.385 20.292 465.385 20.292H33.42c-14.266 0-16.021 18.833-16.021 18.833s-1.924 172.892-.529 279.07c3.87 57.21 61.058 63.076 61.058 63.076s195.155-.57 282.462-1.14c57.558-10.083 63.339-60.573 62.769-88.188 102.713 5.707 175.182-66.771 156.923-163.219"/>
<path style="fill:#ff5f5f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.00346" d="M216.99 306.032c4.46 2.246 7.31-.544 7.31-.544s65.27-59.573 94.674-93.882c26.154-30.691 27.858-82.413-17.056-101.739-44.913-19.324-81.866 22.736-81.866 22.736-32.046-35.245-80.546-33.46-102.979-9.608-22.431 23.852-14.598 64.791 2.137 87.576 15.709 21.388 84.757 82.93 95.222 93.338 0 0 .763.798 2.557 2.123"/>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

@ -1,5 +1,9 @@
var notyf = new Notyf();
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
const MusicKitObjects = {
LibraryPlaylist: function () {
this.id = "";
@ -84,8 +88,14 @@ function fallbackinitMusicKit() {
}
function initMusicKit() {
if(!this.responseText) {
console.log("Using stored token")
this.responseText = JSON.stringify({
token: localStorage.getItem("lastToken")
})
}
let parsedJson = JSON.parse(this.responseText);
localStorage.setItem("lastToken", parsedJson.token);
MusicKit.configure({
developerToken: parsedJson.token,
app: {
@ -116,7 +126,13 @@ function capiInit() {
request.addEventListener("load", initMusicKit);
request.onreadystatechange = function (aEvt) {
if (request.readyState == 4) {
if (request.status != 200) fallbackinitMusicKit();
if (request.status != 200) {
if(localStorage.getItem("lastToken") != null) {
initMusicKit()
}else{
fallbackinitMusicKit()
}
};
}
};
request.open("GET", "https://api.cider.sh/v1/");

View file

@ -239,6 +239,12 @@ input[type=range].md-slider::-webkit-slider-runnable-track {
width: auto;
}
@media only screen and (min-width: 1133px) and (max-width: 1233px) {
.row .col-auto {
display: none !important;
}
}
.col-1 {
flex: 0 0 auto;
width: 8.33333333%;

View file

@ -2642,6 +2642,12 @@ fieldset:disabled .btn {
width: auto;
}
@media only screen and (min-width: 1133px) and (max-width: 1241px) {
.row .col-auto {
display: none !important;
}
}
.col-1 {
flex : 0 0 auto;
width: 8.33333333%;

View file

@ -984,11 +984,11 @@
/* mediaitem-square */
.cd-mediaitem-square {
--transitionDuration: .25s;
--transitionDuration: .5s;
--scaleRate: 1.25;
--scaleRateArtwork: 1;
width: 200px;
height: 200px;
width: calc(160px * var(--windowRelativeScale));
height: calc(200px * var(--windowRelativeScale));
display: inline-flex;
flex: 0 0 auto;
flex-direction: column;
@ -996,14 +996,13 @@
justify-content: center;
align-items: center;
border-radius: 6px;
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
.artwork-container {
position: relative;
.artwork {
height: 150px;
width: 150px;
height: calc(140px * var(--windowRelativeScale));
width: calc(140px * var(--windowRelativeScale));
background: blue;
border-radius: var(--mediaItemRadius);
background: var(--artwork);
@ -1011,7 +1010,6 @@
flex: 0 0 auto;
margin: 6px;
cursor: pointer;
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
.mediaitem-artwork {
box-shadow: unset;
@ -1085,31 +1083,31 @@
}
}
&:not(.mediaitem-card):not(.mediaitem-brick):not(.mediaitem-video):not(.noscale) {
@media (min-width: 1460px) {
--scaleRate: 1.1;
--scaleRateArtwork: 0.9;
width: calc(200px * var(--scaleRate));
height: calc(200px * var(--scaleRate));
// &:not(.mediaitem-card):not(.mediaitem-brick):not(.mediaitem-video):not(.noscale) {
// @media (min-width: 1460px) {
// --scaleRate: 1.1;
// --scaleRateArtwork: 0.9;
// width: calc(200px * var(--scaleRate));
// height: calc(200px * var(--scaleRate));
.artwork-container > .artwork {
width: calc(190px * var(--scaleRateArtwork));
height: calc(190px * var(--scaleRateArtwork));
}
}
// .artwork-container > .artwork {
// width: calc(190px * var(--scaleRateArtwork));
// height: calc(190px * var(--scaleRateArtwork));
// }
// }
@media (min-width: 1550px) {
--scaleRate: 1.25;
--scaleRateArtwork: 1;
width: calc(200px * var(--scaleRate));
height: calc(200px * var(--scaleRate));
// @media (min-width: 1550px) {
// --scaleRate: 1.25;
// --scaleRateArtwork: 1;
// width: calc(200px * var(--scaleRate));
// height: calc(200px * var(--scaleRate));
.artwork-container > .artwork {
width: calc(190px * var(--scaleRateArtwork));
height: calc(190px * var(--scaleRateArtwork));
}
}
}
// .artwork-container > .artwork {
// width: calc(190px * var(--scaleRateArtwork));
// height: calc(190px * var(--scaleRateArtwork));
// }
// }
// }
.info-rect {
@ -1161,10 +1159,12 @@
&.mediaitem-video {
height: 200px;
width: 240px;
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
.artwork {
height: 120px;
width: 212px;
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
}
&:not(.noscale) {
@ -1197,10 +1197,12 @@
&.mediaitem-brick {
height: 200px;
width: 240px;
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
.artwork {
height: 123px;
width: 220px;
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
}
&:not(.noscale) {
@ -1231,12 +1233,14 @@
}
&.mediaitem-small {
width: 140px;
height: 180px;
width: calc(140px, var(--windowRelativeScale));
height: calc(180px, var(--windowRelativeScale));
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
.artwork {
height: 128px;
width: 128px;
height: calc(128px, var(--windowRelativeScale));
width: calc(128px, var(--windowRelativeScale));
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
}
}
@ -1249,6 +1253,7 @@
position: relative;
border-radius: calc(var(--mediaItemRadius) * 2);
box-shadow: var(--mediaItemShadow-ShadowSubtle);
transition: width var(--transitionDuration) linear, height var(--transitionDuration) linear;
.artwork {
width: 230px;
@ -1341,7 +1346,7 @@
}
&:not(.noscale) {
@media (min-width: 1460px) {
@media (min-width: 1200px) {
width: calc(230px * 1.1);
height: calc(298px * 1.1);
.artwork-container > .artwork {
@ -1350,7 +1355,7 @@
}
}
@media (min-width: 1550px) {
@media (min-width: 1400px) {
width: calc(230px * 1.25);
height: calc(298px * 1.25);
.artwork-container > .artwork {

View file

@ -1,6 +1,6 @@
body[platform="darwin"] {
html {
background: transparent!important;
background: transparent !important;
}
&.notransparency::before {
@ -11,6 +11,7 @@ body[platform="darwin"] {
&.simplebg {
background: transparent;
}
&::before {
display: none;
}
@ -26,6 +27,7 @@ body[platform="darwin"] {
.app-chrome .app-chrome-item.search {
margin-right: 12px;
}
.app-chrome .app-mainmenu {
width: 46px;
}
@ -35,15 +37,20 @@ body[platform="darwin"] {
}
}
// &::after {
// position: fixed;
// top:0;left:0;right:0;bottom:0;
// box-shadow: inset 0px 0px .5px 1px rgb(200 200 200 / 40%);
// border-radius: 10px;
// content: " ";
// z-index: 999999;
// pointer-events: none;
// }
&[window-state="normal"] {
&::after {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
box-shadow: inset 0px 0px .5px 1px rgb(200 200 200 / 40%);
border-radius: 10px;
content: " ";
z-index: 999999;
pointer-events: none;
}
}
}
#app-main {
@ -58,6 +65,13 @@ body[platform="darwin"] {
}
}
.settings-window.maxed {
.tabs>.col-auto {
transition: padding-top .3s linear;
padding-top: var(--chromeHeight1);
}
}
#apple-music-video-player-controls #player-exit {
margin-top: 18px;
left: 70px;

View file

@ -23,8 +23,7 @@
.github-themes-page {
display: flex;
flex-direction: column;
padding: 0px;
height: calc(100% - var(--navigationBarHeight));
height: 100%;
.github-avatar {
height: 42px;
@ -52,9 +51,11 @@
.repos-list {
height: 100%;
overflow-y: overlay;
width: 320px;
font-size: 14px;
overflow: overlay;
padding-bottom: 16px;
flex: 0 0 auto;
> .list-group {
margin: 0px;
@ -76,9 +77,9 @@
.github-preview {
height: 100%;
flex: 1;
background: var(--color2);
padding: 16px 32px;
overflow-y: overlay;
overflow: auto;
padding-bottom: 16px;
}
.gh-content {
@ -90,6 +91,182 @@
.gh-header {
padding: 16px;
height: 64px;
display: grid;
align-content: center;
flex: 0 0 auto;
.header-text {
position: initial !important;
justify-content: left !important;
}
}
.installed-themes-page {
.style-editor-container {
height: 100%;
flex: 1;
background: var(--color2);
padding: 0px;
overflow-y: overlay;
.list-group-item {
border-radius: 0px;
}
}
}
}
//Styles Page
.installed-themes-page {
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
.themeContextMenu {
background: transparent;
color: var(--keyColor);
border: 0px;
}
.list-group-item {
&.addon {
background: rgb(86 86 86 / 20%);
}
&.applied {
background: var(--keyColor-disabled);
pointer-events: none;
}
}
.repo-header {
font-size: 16px;
position: sticky;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 50px;
z-index: 1;
background: rgba(36, 36, 36, 0.5);
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: var(--glassFilter);
overflow: hidden;
border-bottom: 1px solid rgb(0 0 0 / 18%);
border-top: 1px solid rgb(135 135 135 / 18%);
}
.gh-header {
z-index: 5;
padding: 16px;
flex: 0 0 auto;
height: 64px;
display: grid;
align-content: center;
.header-text {
position: initial !important;
justify-content: left !important;
}
}
.gh-content {
display: flex;
flex-direction: row;
padding: 0px;
height: 100%;
flex: 0 0 auto;
.repos-list {
width: 320px;
overflow: overlay;
height: 90%;
font-size: 14px;
white-space: nowrap;
> .list-group {
margin: 0px;
padding-bottom: 16px;
}
.list-group-item {
padding: 12px 6px;
&:hover {
filter: brightness(1.2);
}
&:active {
filter: brightness(0.8);
}
}
}
.style-editor-container {
height: 100%;
flex: 1;
padding: 0px;
width: 100%;
overflow: hidden;
.stylestack-editor {
padding-bottom: 16px;
}
.list-group-item {
border-radius: 0px;
}
}
}
.stylestack-editor {
width: 100%;
.btn,
.btn-group {
width: 100%;
}
.themeLabel {
display: flex;
align-items: center;
}
.handle {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.list-group-item {
&:hover {
cursor: grab;
}
&:active {
cursor: grabbing;
}
}
.removeItem {
border: 0px;
background: transparent;
height: 32px;
font-weight: bold;
color: var(--textColor);
cursor: pointer;
}
.stylesDropdown {
> .dropdown-menu {
height: 300px;
overflow-y: overlay;
}
}
}
}
@ -1053,7 +1230,7 @@
}
&.animated .artist-header {
min-height: 500px;
min-height: 80vh;
}
.artist-header {
@ -1113,6 +1290,24 @@
right: 28px;
}
.social-btn {
border-radius: 100%;
background: transparent;
height: 17px;
border: 0px;
cursor: pointer;
z-index: 69;
display: flex;
justify-content: center;
align-items: center;
float: right;
}
@media only screen and (min-width: 1133px) and (max-width: 1277px) {
.social-btn {
display: none !important;
}
}
.animated {
width: 100%;
height: 100%;
@ -1131,6 +1326,7 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
object-fit: cover;
}
}
@ -1273,107 +1469,6 @@
/* Artist Page End */
.installed-themes-page {
.themeContextMenu {
background: transparent;
color: var(--keyColor);
border: 0px;
}
.list-group-item {
&.addon {
background: rgb(86 86 86 / 20%);
}
&.applied {
background: var(--keyColor-disabled);
pointer-events: none;
}
}
.repo-header {
font-size: 16px;
position: sticky;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 50px;
z-index: 1;
background: rgba(36, 36, 36, 0.5);
display: flex;
justify-content: center;
align-items: center;
backdrop-filter: var(--glassFilter);
overflow: hidden;
border-bottom: 1px solid rgb(0 0 0 / 18%);
border-top: 1px solid rgb(135 135 135 / 18%);
}
.style-editor-container {
height: 100%;
flex: 1;
background: var(--color2);
padding: 0px;
overflow-y: overlay;
.list-group-item {
border-radius: 0px;
}
}
.stylestack-editor {
width: 100%;
.btn,
.btn-group {
width: 100%;
}
.themeLabel {
display: flex;
align-items: center;
}
.handle {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.list-group-item {
&:hover {
cursor: grab;
}
&:active {
cursor: grabbing;
}
}
.removeItem {
border: 0px;
background: transparent;
height: 32px;
font-weight: bold;
color: var(--textColor);
cursor: pointer;
}
.stylesDropdown {
> .dropdown-menu {
height: 300px;
overflow-y: overlay;
}
}
}
}
// Settings page
.settings-page {
padding: 0px;
@ -1987,7 +2082,7 @@
.settings-window {
background: var(--baseColorMix);
max-width: 80%;
max-width: 90%;
max-height: 90%;
width: 100%;
height: 100%;
@ -2024,6 +2119,11 @@
display: flex;
gap: 10px;
align-items: center;
height: 35px;
:nth-child(2) {
white-space: nowrap;
}
}
@ -2082,6 +2182,11 @@
background-color: rgb(196, 43, 28)
}
&.back-btn {
left: 10px;
right: unset;
}
&.minmax-btn {
right: 52px;
@ -2109,6 +2214,9 @@
> .col-auto {
width: 230px;
overflow-x: hidden;
overflow-y: overlay;
transition: width 0.25s ease-in-out;
}
.tab-content {
@ -2120,9 +2228,50 @@
overflow-y: overlay;
height: 100%;
background-color: var(--panelColor2);
padding:0px;
padding-top: 48px;
border-left: 1px solid var(--borderColor);
}
.github-themes-page, .installed-themes-page {
.header-text {
font-size: 1.25em;
}
}
.tab-pane {
height:100%;
}
.settings-tab-content {
height:100%;
}
&.no-sidebar {
.gh-header {
>.row {
&:last-child {
padding-right: 90px;
}
}
}
.tab-content {
padding-top:0px;
}
.tabs {
.nav-pills .nav-link {
width: 50px;
:nth-child(2) {
// font-size: 0px;
opacity:0;
}
}
>.col-auto {
width: 80px;
}
}
}
}
}

View file

@ -12,6 +12,7 @@ const app = new Vue({
ipcRenderer: ipcRenderer,
cfg: ipcRenderer.sendSync("getStore"),
isDev: ipcRenderer.sendSync("is-dev"),
clientPort: ipcRenderer.sendSync("get-port"),
drawertest: false,
platform: "",
mk: {},
@ -705,6 +706,9 @@ const app = new Vue({
} catch (err) {
}
// Used to get a scale factor for the window for CSS scaling
window.addEventListener("resize", e => this.setWindowScaleFactor())
this.setWindowScaleFactor()
this.mk._bag.features['seamless-audio-transitions'] = this.cfg.audio.seamless_audio
this.mk._bag.features["broadcast-radio"] = true
this.mk._services.apiManager.store.storekit._restrictedEnabled = false
@ -915,13 +919,19 @@ const app = new Vue({
}
});
this.mk.addEventListener(MusicKit.Events.playbackProgressDidChange, () => {
if (self.mk.currentPlaybackProgress === (app.cfg.connectivity.lastfm.scrobble_after / 100)) {
ipcRenderer.send('lastfm:scrobbleTrack', MusicKitInterop.getAttributes());
}
})
this.mk.addEventListener(MusicKit.Events.playbackStateDidChange, (event) => {
ipcRenderer.send('wsapi-updatePlaybackState', wsapi.getAttributes());
document.body.setAttribute("playback-state", event.state == 2 ? "playing" : "paused")
})
this.mk.addEventListener(MusicKit.Events.playbackTimeDidChange, (a) => {
self.lyriccurrenttime = self.mk.currentPlaybackTime + app.lyricOffset
// self.lyriccurrenttime = self.mk.currentPlaybackTime - app.lyricOffset
this.currentSongInfo = a
self.playerLCD.playbackDuration = (self.mk.currentPlaybackTime)
// wsapi
@ -1091,6 +1101,18 @@ const app = new Vue({
ipcRenderer.invoke("scanLibrary")
},
setWindowScaleFactor() {
let scale = window.devicePixelRatio * window.innerWidth / 1280 * window.innerHeight / 720
let desiredScale = clamp(parseFloat(app.cfg.visual.maxElementScale == -1 ? 1.5 : app.cfg.visual.maxElementScale), 1, 1.5)
app.$store.state.windowRelativeScale = scale
if(scale <= 1) {
scale = 1
}else if(scale >= desiredScale) {
scale = desiredScale
}
document.documentElement.style
.setProperty('--windowRelativeScale', scale);
},
showFoo(querySelector, time) {
clearTimeout(this.idleTimer);
if (this.idleState == true) {
@ -1120,7 +1142,7 @@ const app = new Vue({
message: `[Themes] ${theme.name} has an update available.`
})
notify.on("click", () => {
app.appRoute("themes-github")
app.openSettingsPage("github-themes")
notyf.dismiss(notify)
})
}
@ -1944,12 +1966,31 @@ const app = new Vue({
})
return;
} else if(item.attributes.link.url.includes("viewFeature")) {
const params = new Proxy(new URLSearchParams(new URL(item.attributes.link.url).search), {
get: (searchParams, prop) => searchParams.get(prop),
});
id = params.id
app.mk.api.v3.music(`/v1/editorial/vn/multiplex/${id}?art%5Burl%5D=f&format%5Bresources%5D=map&platform=web`).then(
(data) => {
let item = data.data.results?.target ?? []
app.routeView(item)
}
)
} else {
window.open(item.attributes.link.url)
}
}
} else if (kind == "multirooms") {
} else if (kind == "multiplex") {
app.mk.api.v3.music(`/v1/editorial/vn/multiplex/${id}?art%5Burl%5D=f&format%5Bresources%5D=map&platform=web`).then(
(data) => {
let item = data.data.results?.target ?? []
app.routeView(item)
}
)
}if (kind == "multirooms") {
app.getTypeFromID("multiroom", id, false, {
platform: "web",
extend: "editorialArtwork,uber,lockupStyle"
@ -1990,7 +2031,7 @@ const app = new Vue({
params["fields[artists]"] = "name,url"
params["omit[resource]"] = "autos"
params["meta[albums:tracks]"] = 'popularity'
params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialNotes,editorialVideo,name,playParams,releaseDate,url,copyright"
params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialNotes,editorialVideo,name,playParams,releaseDate,url,copyright,genreNames"
}
if (kind.includes("playlist") || kind.includes("album")) {
app.page = (kind) + "_" + (id);
@ -3019,7 +3060,10 @@ const app = new Vue({
const track = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.title ?? '' : '');
const artist = encodeURIComponent((this.mk.nowPlayingItem != null) ? this.mk.nowPlayingItem.artistName ?? '' : '');
const time = encodeURIComponent((this.mk.nowPlayingItem != null) ? (Math.round((this.mk.nowPlayingItem.attributes["durationInMillis"] ?? -1000) / 1000) ?? -1) : -1);
const id = encodeURIComponent((this.mk.nowPlayingItem != null) ? app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem["songId"] ?? '') : '');
let id = null; let vanity_id = null;
if (this.mk.nowPlayingItem != null && app.mk.nowPlayingItem.localFilesMetadata != null) {const id = encodeURIComponent('')}
else {id = encodeURIComponent((this.mk.nowPlayingItem != null) ? (app.mk.nowPlayingItem._songId) ?? (app.mk.nowPlayingItem["songId"] ?? '') : '');}
let lrcfile = "";
let richsync = [];
const lang = app.cfg.lyrics.mxm_language // translation language
@ -3027,67 +3071,13 @@ const app = new Vue({
return Math.random().toString(36).replace(/[^a-z]+/g, '').slice(2, 10);
}
/* get token */
function getToken(mode, track, artist, songid, lang, time, id) {
if (attempt > 2) {
app.loadNeteaseLyrics();
// app.loadAMLyrics();
} else {
attempt = attempt + 1;
let url = "https://apic-desktop.musixmatch.com/ws/1.1/token.get?app_id=web-desktop-app-v1.0&t=" + revisedRandId();
let req = new XMLHttpRequest();
req.overrideMimeType("application/json");
req.open('GET', url, true);
req.setRequestHeader("authority", "apic-desktop.musixmatch.com");
req.onload = function () {
try {
let jsonResponse = JSON.parse(this.responseText);
let status2 = jsonResponse["message"]["header"]["status_code"];
if (status2 == 200) {
let token = jsonResponse["message"]["body"]["user_token"] ?? '';
if (token != "" && token != "UpgradeOnlyUpgradeOnlyUpgradeOnlyUpgradeOnly") {
console.debug('200 token', mode);
// token good
app.mxmtoken = token;
if (mode == 1) {
getMXMSubs(track, artist, app.mxmtoken, lang, time, id);
} else {
getMXMTrans(songid, lang, app.mxmtoken);
}
} else {
console.debug('fake 200 token');
getToken(mode, track, artist, songid, lang, time)
}
} else {
// console.log('token 4xx');
getToken(mode, track, artist, songid, lang, time)
}
} catch (e) {
console.log('error');
app.loadQQLyrics();
//app.loadAMLyrics();
}
};
req.onerror = function () {
console.log('error');
app.loadQQLyrics();
// app.loadAMLyrics();
};
req.send();
}
}
function getMXMSubs(track, artist, token, lang, time, id) {
let usertoken = encodeURIComponent(token);
let richsyncQuery = (app.cfg.lyrics.mxm_karaoke) ? "&optional_calls=track.richsync" : ""
let timecustom = (!time || (time && time < 0)) ? '' : `&f_subtitle_length=${time}&q_duration=${time}&f_subtitle_length_max_deviation=40`;
let itunesid = (id && id != "") ? `&track_itunes_id=${id}` : '';
let url = "https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&namespace=lyrics_richsynched" + richsyncQuery + "&subtitle_format=lrc&q_artist=" + artist + "&q_track=" + track + itunesid + "&usertoken=" + usertoken + timecustom + "&app_id=web-desktop-app-v1.0&t=" + revisedRandId();
function getMXMSubs(track, artist, lang, time, id) {
let richsyncQuery = app.cfg.lyrics.mxm_karaoke
let itunesid = (id && id != "") ? id : ''; // Mode 1 -> Subs
let url = "https://api.cider.sh/v1/lyrics?" + "mode=1" + "&richsyncQuery=" + richsyncQuery + "&track=" + track + "&artist=" + artist + "&songID=" + itunesid + "&source=mxm" + "&lang=" + lang + "&time=" + time;
let req = new XMLHttpRequest();
req.overrideMimeType("application/json");
req.open('GET', url, true);
req.setRequestHeader("authority", "apic-desktop.musixmatch.com");
req.onload = function () {
try {
let jsonResponse = JSON.parse(this.responseText);
@ -3095,11 +3085,13 @@ const app = new Vue({
let status1 = jsonResponse["message"]["header"]["status_code"];
if (status1 == 200) {
let id = '';
let id, songLang = '';
try {
if (jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["header"]["status_code"] == 200 && jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["header"]["status_code"] == 200) {
id = jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["body"]["track"]["track_id"] ?? '';
lrcfile = jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["body"]["subtitle_list"][0]["subtitle"]["subtitle_body"];
vanity_id = jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["body"]["track"]["commontrack_vanity_id"];
songLang = jsonResponse["message"]["body"]["macro_calls"]["track.lyrics.get"]["message"]["body"]["lyrics"]["lyrics_language_description"];
try {
let lrcrich = jsonResponse["message"]["body"]["macro_calls"]["track.richsync.get"]["message"]["body"]["richsync"]["richsync_body"];
@ -3114,7 +3106,7 @@ const app = new Vue({
// app.loadAMLyrics()
} else {
if (richsync == [] || richsync.length == 0) {
console.log("ok");
console.log("musixmatch worki");
// process lrcfile to json here
app.lyricsMediaItem = lrcfile
let u = app.lyricsMediaItem.split(/[\r\n]/);
@ -3155,24 +3147,21 @@ const app = new Vue({
});
app.lyrics = preLrc;
}
if (lrcfile != null && lrcfile != '') {
// load translation
getMXMTrans(id, lang, token);
} else {
// app.loadAMLyrics()
app.loadQQLyrics();
// Load translation
if (songLang.toLowerCase() !== lang){
getMXMTrans(lang, vanity_id);
}
}
} catch (e) {
console.log(e);
app.loadQQLyrics();
// app.loadAMLyrics()
}
} else { //4xx rejected
getToken(1, track, artist, '', lang, time);
}
}
} catch (e) {
console.log(e);
console.error(e);
app.loadQQLyrics();
//app.loadAMLyrics()
}
@ -3182,59 +3171,59 @@ const app = new Vue({
console.log('error');
// app.loadAMLyrics();
};
req.open('POST', url, true);
req.send();
}
function getMXMTrans(id, lang, token) {
if (lang != "disabled" && id != '') {
let usertoken = encodeURIComponent(token);
let url2 = "https://apic-desktop.musixmatch.com/ws/1.1/crowd.track.translations.get?translation_fields_set=minimal&selected_language=" + lang + "&track_id=" + id + "&comment_format=text&part=user&format=json&usertoken=" + usertoken + "&app_id=web-desktop-app-v1.0&t=" + revisedRandId();
let req2 = new XMLHttpRequest();
req2.overrideMimeType("application/json");
req2.open('GET', url2, true);
req2.setRequestHeader("authority", "apic-desktop.musixmatch.com");
req2.onload = function () {
try {
let jsonResponse2 = JSON.parse(this.responseText);
console.log(jsonResponse2);
let status2 = jsonResponse2["message"]["header"]["status_code"];
if (status2 == 200) {
try {
let preTrans = []
let u = app.lyrics;
let translation_list = jsonResponse2["message"]["body"]["translations_list"];
if (translation_list.length > 0) {
for (var i = 0; i < u.length - 1; i++) {
preTrans[i] = ""
for (var trans_line of translation_list) {
if (u[i].line == " " + trans_line["translation"]["matched_line"] || u[i].line == trans_line["translation"]["matched_line"]) {
u[i].translation = trans_line["translation"]["description"];
break;
}
}
}
app.lyrics = u;
function getMXMTrans(lang, vanity_id) {
try {
if (lang != "disabled" && vanity_id != '') { // Mode 2 -> Trans
fetch('https://www.musixmatch.com/lyrics/' + vanity_id +'/translation/' + lang, {
method: 'GET',
headers: {
'Host': 'musixmatch.com',
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
'authority': "www.musixmatch.com"
},
})
.then(async (res) => {
if (res.status != 200) {return}
let html = document.createElement('html'); html.innerHTML = await res.text()
let lyric_isolated = html.querySelector("#site > div > div > div > main > div > div > div.mxm-track-lyrics-container > div.container > div > div > div > div.col-sm-12.col-md-10.col-ml-9.col-lg-9 > div.mxm-lyrics.translated > div.row > div.col-xs-12.col-sm-12.col-md-12.col-ml-12.col-lg-12")
let raw_lines = lyric_isolated.getElementsByClassName("col-xs-6 col-sm-6 col-md-6 col-ml-6 col-lg-6")
let applied = 0;
for (let i = 1; applied < app.lyrics.length; i+=2) { // Start on odd elements because even ones are original.
if (raw_lines[i].childNodes[0].childNodes[0].textContent.trim() == "") {i+=2;}
if (app.lyrics[applied].line.trim() == "") {applied+=1;}
if (app.lyrics[applied].line.trim() === raw_lines[i].childNodes[0].childNodes[0].textContent.trim().replace('', "'")) {
// Do Nothing
applied +=1;
}
} catch (e) {
/// not found trans -> ignore
else {
if (app.lyrics[applied].line === "lrcInstrumental") {
if (app.lyrics[applied+1].line.trim() === raw_lines[i].childNodes[0].childNodes[0].textContent.trim()) {
// Do Nothing
applied +=2;
}
else {
app.lyrics[applied+1].translation = raw_lines[i].childNodes[0].childNodes[0].textContent.trim();
applied +=2;
}
}
else {
app.lyrics[applied].translation = raw_lines[i].childNodes[0].childNodes[0].textContent.trim();
applied +=1;
}
}
}
} else { //4xx rejected
getToken(2, '', '', id, lang, '');
}
} catch (e) {
}
})
}
req2.send();
}
} catch (e) {console.debug("Error while parsing MXM Trans: " + e)}
}
if (track != "" & track != "No Title Found") {
if (app.mxmtoken != null && app.mxmtoken != '') {
getMXMSubs(track, artist, app.mxmtoken, lang, time, id)
} else {
getToken(1, track, artist, '', lang, time);
}
getMXMSubs(track, artist, lang, time, id);
}
},
loadNeteaseLyrics() {
@ -3976,9 +3965,8 @@ const app = new Vue({
this.currentArtUrl = this.mk.nowPlayingItem._assets[0].artworkURL
}
try {
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
} catch (e) {
}
// document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
} catch (e) {}
} else {
let data = await this.mk.api.v3.music(`/v1/me/library/songs/${this.mk.nowPlayingItem.id}`);
data = data.data.data[0];
@ -3990,14 +3978,14 @@ const app = new Vue({
}
ipcRenderer.send('updateRPCImage', this.currentArtUrl ?? '');
try {
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
// document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
} catch (e) {
}
} else {
this.currentArtUrlRaw = ''
this.currentArtUrl = '';
try {
document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
// document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);
} catch (e) {
}
}
@ -4441,21 +4429,30 @@ const app = new Vue({
case "audiolabs":
this.$store.state.pageState.settings.currentTabIndex = 2
break;
case "visual":
case "styles":
this.$store.state.pageState.settings.currentTabIndex = 3
break;
case "lyrics":
case "visual":
this.$store.state.pageState.settings.currentTabIndex = 4
break;
case "connectivity":
case "github-plugins":
this.$store.state.pageState.settings.currentTabIndex = 5
break;
case "advanced":
case "lyrics":
this.$store.state.pageState.settings.currentTabIndex = 6
break;
case "keybindings":
case "connectivity":
this.$store.state.pageState.settings.currentTabIndex = 7
break;
case "advanced":
this.$store.state.pageState.settings.currentTabIndex = 8
break;
case "keybindings":
this.$store.state.pageState.settings.currentTabIndex = 9
break;
case "github-themes":
this.$store.state.pageState.settings.currentTabIndex = 10
break;
}
app.modals.settings = true
},

View file

@ -1,5 +1,6 @@
const store = new Vuex.Store({
state: {
windowRelativeScale: 1,
library: {
// songs: ipcRenderer.sendSync("get-library-songs"),
// albums: ipcRenderer.sendSync("get-library-albums"),

View file

@ -14,6 +14,7 @@
@import url("less/pages.less");
:root {
--windowRelativeScale: 1;
--appleEase: cubic-bezier(0.42, 0, 0.58, 1);
--borderColor: rgb(200 200 200 / 16%);
--mediaItemShadow: inset 0px 0px 0px 1px rgb(200 200 200 / 16%);
@ -1885,6 +1886,25 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
}
}
.social-btn {
border-radius: 100%;
background: transparent;
height: 17px;
border: 0px;
cursor: pointer;
z-index: 69;
display: flex;
justify-content: center;
align-items: center;
float: right;
}
@media only screen and (min-width: 1133px) and (max-width: 1277px) {
.social-btn {
display: none !important;
}
}
.about-page {
.teamBtn {
display: flex;
@ -2037,7 +2057,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb {
// screen size > 1200px
@media screen and (min-width: 1500px) {
grid-template-columns: repeat(6, minmax(200px, 1fr));
grid-template-columns: repeat(5, minmax(200px, 1fr));
}
// less than 1100px
@media screen and (max-width: 1150px) {

View file

@ -146,7 +146,7 @@
<img v-if="!(cfg.visual.bg_artwork_rotation && animateBackground)" class="bg-artwork no-animation" :src="$store.state.artwork.playerLCD">
</div>
</div>
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="lyriccurrenttime" :lyrics="lyrics"
<lyrics-view v-if="drawer.panel == 'lyrics'" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
:richlyrics="richlyrics"></lyrics-view>
<div v-if="drawer.panel == 'lyrics'" class="lyric-footer">
<button class="md-btn" @click="modularUITest(!fullscreenLyrics)">{{fullscreenLyrics ?

View file

@ -5,7 +5,7 @@
<div class="app-playback-controls" @mouseover="chrome.progresshover = true"
@mouseleave="chrome.progresshover = false" @contextmenu="nowPlayingContextMenu">
<div class="artwork" id="artworkLCD">
<mediaitem-artwork :url="currentArtUrl"></mediaitem-artwork>
<mediaitem-artwork :url="$root.currentArtUrl"></mediaitem-artwork>
</div>
<b-popover custom-class="mediainfo-popover" target="artworkLCD" triggers="hover" placement="right">
<div class="content">

View file

@ -1,6 +1,7 @@
<script type="text/x-template" id="mediaitem-artwork">
<div class="mediaitem-artwork" :style="awStyle" @contextmenu="contextMenu" :class="[{'rounded': (type == 'artists')}, classes]" :key="url">
<img :src="app.getMediaItemArtwork(url, size, width)"
<img :src="imgSrc"
ref="image"
decoding="async"
loading="lazy"
:style="imgStyle"
@ -47,6 +48,10 @@
shadow: {
type: String,
default: ''
},
upscaling: {
type: Boolean,
default: false
}
},
data: function () {
@ -63,15 +68,37 @@
opacity: 0,
transition: "opacity .25s linear"
},
classes: []
classes: [],
imgSrc: ""
}
},
computed: {
windowRelativeScale: function () {
return app.$store.state.windowRelativeScale;
}
},
watch: {
windowRelativeScale: function (newValue, oldValue) {
this.swapImage(newValue)
},
url: function (newValue, oldValue) {
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
}
},
mounted() {
this.getClasses()
this.imgSrc = app.getMediaItemArtwork(this.url, this.size, this.width)
},
methods: {
swapImage(newValue) {
if(!this.upscaling || window.devicePixelRatio !== 1) return
if (newValue > 1.5) {
this.imgSrc = app.getMediaItemArtwork(this.url, parseInt(this.size * 2.0), parseInt(this.size * 2.0));
}
},
imgLoaded() {
this.imgStyle.opacity = 1
this.swapImage(app.$store.state.windowRelativeScale)
// this.awStyle.background = ""
},
contextMenu(event) {

View file

@ -16,7 +16,7 @@
@controller-click="route()"
tabindex="0"
:class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]">
<div v-if="isVisible" class="listitem-content">
<div v-show="isVisible" class="listitem-content">
<div class="popular" v-if="!showInLibrary && item?.meta?.popularity != null && item?.meta?.popularity > 0.7"></div>
<div class="isLibrary" v-if="showLibraryStatus == true">
<div v-if="showInLibrary" :style="{display: (showInLibrary ? 'block' : 'none'), 'margin-left':'11px'}">

View file

@ -17,6 +17,7 @@
:url="getArtworkUrl()"
:video="(item.attributes != null && item.attributes.editorialVideo != null) ? (item.attributes.editorialVideo.motionDetailSquare ? item.attributes.editorialVideo.motionDetailSquare.video : (item.attributes.editorialVideo.motionSquareVideo1x1 ? item.attributes.editorialVideo.motionSquareVideo1x1.video : '')) : '' "
:size="size"
:upscaling="true"
shadow="subtle"
:bgcolor="getBgColor()"
:video-priority="forceVideo"

View file

@ -0,0 +1,323 @@
<script type="text/x-template" id="keybinds-settings">
<div class="keybinds-page">
<div class="md-option-header">
<span>{{$root.getLz('settings.option.general.keybindings')}}</span>
</div>
<div class="settings-option-body">
<div class="md-option-header-sub">
<span>{{$root.getLz('settings.option.general.keybindings.library')}}</span>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.search')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('search')">
{{app.cfg.general.keybindings.search.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.listnow')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('listnow')">
{{app.cfg.general.keybindings.listnow.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.browse')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('browse')">
{{app.cfg.general.keybindings.browse.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.recentAdd')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('recentAdd')">
{{app.cfg.general.keybindings.recentAdd.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.songs')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('songs')">
{{app.cfg.general.keybindings.songs.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.albums')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('albums')">
{{app.cfg.general.keybindings.albums.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.artists')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('artists')">
{{app.cfg.general.keybindings.artists.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-header-sub">
<span>{{$root.getLz('settings.option.general.keybindings.session')}}</span>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.private')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('togglePrivateSession')">
{{app.cfg.general.keybindings.togglePrivateSession.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-header-sub">
<span>{{$root.getLz('settings.option.general.keybindings.control')}}</span>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.remote')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('webRemote')">
{{app.cfg.general.keybindings.webRemote.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.audio')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('audioSettings')">
{{app.cfg.general.keybindings.audioSettings.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.plugins')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('pluginMenu')">
{{app.cfg.general.keybindings.pluginMenu.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.cast')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('castToDevices')">
{{app.cfg.general.keybindings.castToDevices.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.settings')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('settings')">
{{app.cfg.general.keybindings.settings.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-header-sub" v-if="app.platform !== 'darwin'">
<span>{{$root.getLz('settings.option.general.keybindings.interface')}}</span>
</div>
<div class="md-option-line" v-if="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz('term.zoomin')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('zoomn')">
{{app.cfg.general.keybindings.zoomn.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line" v-if="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz('term.zoomout')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('zoomt')">
{{app.cfg.general.keybindings.zoomt.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-line" v-if="app.platform !== 'darwin'">
<div class="md-option-segment">
{{$root.getLz('term.zoomreset')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('zoomrst')">
{{app.cfg.general.keybindings.zoomrst.join(' + ')}}
</button>
</div>
</div>
<div class="md-option-header-sub">
<span>{{$root.getLz('settings.option.general.keybindings.advanced')}}</span>
</div>
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.description.developer')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<button class="md-btn md-btn-small md-btn-block"
@click="keyBindUpdate('openDeveloperTools')">
{{app.cfg.general.keybindings.openDeveloperTools.join(' + ')}}
</button>
</div>
</div>
<button class="md-btn md-btn-large md-btn-block" @click="keyBindReset()">
{{$root.getLz('term.reset')}}
</button>
</div>
</div>
</script>
<script>
Vue.component('keybinds-settings', {
template: "#keybinds-settings",
props: [],
data: function () {
return {
app: this.$root
}
},
methods: {
keyBindUpdate: function (action) {
const blur = document.createElement('div');
blur.className = 'blur';
blur.style.backgroundColor = 'rgba(0,0,0,0.25)';
blur.style.position = 'fixed';
blur.style.top = '0';
blur.style.left = '0';
blur.style.width = '100%';
blur.style.height = '100%';
blur.style.zIndex = '9999';
blur.style.display = 'flex';
blur.style.alignItems = 'center';
blur.style.justifyContent = 'center';
blur.style.fontSize = '2em';
blur.style.color = 'white';
blur.innerHTML = `<center>${app.getLz('settings.option.general.keybindings.pressCombination')}<br />${app.getLz('settings.option.general.keybindings.pressEscape')}</center>`
document.body.appendChild(blur);
let keyBind = [];
const keyBindTimeout = setTimeout(function () {
keyBind = [];
document.body.removeChild(blur);
}, 30000);
const keyBindUpdate = function (e) {
if (document.body.contains(blur)) {
if (e.key == 'Escape') {
document.body.removeChild(blur);
clearTimeout(keyBindTimeout);
return;
} else {
if (e.keyCode >= 65 && e.keyCode <= 90 && e.keyCode <= 97 && e.keyCode <= 122) {
keyBind.push(e.key.toUpperCase());
} else {
keyBind.push(e.key);
}
if (keyBind.length === 2) {
if (keyBind[0] !== keyBind[1]) {
app.cfg.general.keybindings[action] = keyBind
document.body.removeChild(blur);
clearTimeout(keyBindTimeout);
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
if (ok) ipcRenderer.invoke("relaunchApp")
})
} else {
keyBind = [];
}
}
}
}
};
document.addEventListener('keydown', keyBindUpdate);
},
keyBindReset: function () {
app.cfg.general.keybindings.search = [app.platform == "darwin" ? "Command" : "Control", "F"];
app.cfg.general.keybindings.listnow = [app.platform == "darwin" ? "Command" : "Control", "L"];
app.cfg.general.keybindings.browse = [app.platform == "darwin" ? "Command" : "Control", "B"];
app.cfg.general.keybindings.recentAdd = [app.platform == "darwin" ? "Command" : "Control", "G"];
app.cfg.general.keybindings.songs = [app.platform == "darwin" ? "Command" : "Control", "J"];
app.cfg.general.keybindings.albums = [app.platform == "darwin" ? "Command" : "Control", "A"];
app.cfg.general.keybindings.artists = [app.platform == "darwin" ? "Command" : "Control", "D"];
app.cfg.general.keybindings.togglePrivateSession = [app.platform == "darwin" ? "Command" : "Control", "P"];
app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "W"];
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "A"];
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "P"];
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Command" : "Control",app.platform == "darwin" ? "Option" : (app.platform == "linux" ? "Shift" : "Alt"), "C"];
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Command" : "Control", ","];
app.cfg.general.keybindings.zoomn = [app.platform == "darwin" ? "Command" : "Control", "numadd"];
app.cfg.general.keybindings.zoomt = [app.platform == "darwin" ? "Command" : "Control", "numsub"];
app.cfg.general.keybindings.zoomrst = [app.platform == "darwin" ? "Command" : "Control", "num0"];
app.cfg.general.keybindings.openDeveloperTools = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : "Shift", "I"];
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {
if (ok) ipcRenderer.invoke("relaunchApp")
})
},
getLanguages: function () {
let langs = this.$root.lzListing
let categories = {
"main": [],
"fun": [],
"unsorted": []
}
// sort by category if category is undefined or empty put it in "unsorted"
for (let i = 0; i < langs.length; i++) {
if (langs[i].category === undefined || langs[i].category === "") {
categories.unsorted.push(langs[i])
} else {
categories[langs[i].category].push(langs[i])
}
}
// return
return categories
},
}
})
</script>

View file

@ -0,0 +1,188 @@
<script type="text/x-template" id="plugins-github">
<div class="github-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
<h1 class="header-text">{{$root.getLz('settings.header.visual.plugin.github.page')}}</h1>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="installThemeURL()">
{{$root.getLz('settings.option.visual.plugin.github.download')}}
</button>
</div>
</div>
</div>
<div class="gh-content">
<div class="repos-list">
<ul class="list-group list-group-flush">
<li @click="showRepo(repo)" class="list-group-item list-group-item-dark"
:style="{'background': (repo.id == openRepo.id) ? 'var(--keyColor)' : '', 'border-radius': '5px'}"
v-for="repo in repos">
<div class="row">
<div class="col flex-center">
<div>
<h4 class="repo-name">{{ (repo.description != null) ? repo.description : repo.full_name }}</h4>
<div>⭐ {{ repo.stargazers_count }}</div>
</div>
</div>
</div>
</li>
</ul>
</div>
<div class="github-preview" v-if="openRepo.full_name">
<div class="gh-preview-header">
<div class="row nopadding">
<div class="col nopadding flex-center">
<div>
<h3 class="repo-preview-name">{{ openRepo.description }}</h3>
<div>
<div class="svg-icon inline" :style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
<a class="repo-url" target="_blank" :href="openRepo.html_url">{{ openRepo.full_name
}}</a></div>
<div>⭐ {{ openRepo.stargazers_count }}</div>
</div>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-primary" @click="installThemeRepo(openRepo)">
<span v-if="!themesInstalled.includes(openRepo.full_name)">{{$root.getLz('action.install')}}</span>
<span v-else>{{$root.getLz('action.update')}}</span>
</button>
</div>
</div>
</div>
<hr>
<div v-html="openRepo.readme" class="github-content"></div>
</div>
<div class="github-preview" v-else>
</div>
</transition>
</div>
</div>
</script>
<script>
Vue.component('plugins-github', {
template: "#plugins-github",
props: [],
data: function () {
return {
repos: [],
openRepo: {
id: -1,
name: '',
description: '',
html_url: '',
stargazers_count: 0,
owner: {
avatar_url: ''
},
readme: ""
},
themesInstalled: []
}
},
mounted() {
this.getRepos();
// this.getInstalledThemes();
},
methods: {
getInstalledThemes() {
let self = this
const themes = ipcRenderer.sendSync("get-themes")
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
themes.forEach(theme => {
if (theme.github_repo !== "") {
self.themesInstalled.push(theme.github_repo)
}
})
},
showRepo(repo) {
const self = this
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch(readmeUrl, requestOptions)
.then(response => response.text())
.then(result => {
self.openRepo = repo
self.openRepo.readme = self.convertReadMe(result);
})
.catch(error => {
self.openRepo = repo
self.openRepo.readme = `This repository doesn't have a README.md file.`;
console.log('error', error)
});
},
convertReadMe(text) {
return marked.parse(text)
},
installThemeRepo(repo) {
let self = this
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.plugin.github.install.confirm'), {
repo: repo.full_name
});
app.confirm(msg, (res) => {
if (res) {
ipcRenderer.once("plugin-installed", (event, arg) => {
if (arg.success) {
self.themes = []
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
if (ok) {
ipcRenderer.invoke("relaunchApp")
} else {
return
}
})
} else {
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
}
});
ipcRenderer.invoke("get-github-plugin", repo.html_url)
}
})
},
installThemeURL() {
let self = this
app.prompt(app.getLz('settings.prompt.visual.plugin.github.URL'), (result) => {
if (result) {
ipcRenderer.once("plugin-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
app.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
if (ok) {
ipcRenderer.invoke("relaunchApp")
} else {
return
}
})
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.plugin.install.error'));
}
});
ipcRenderer.invoke("get-github-plugin", result)
}
});
},
getRepos() {
let self = this
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch("https://api.github.com/search/repositories?q=topic:cidermusicplugin fork:true&per_page=100", requestOptions)
.then(response => response.text())
.then(result => {
self.repos = JSON.parse(result).items
})
.catch(error => console.log('error', error));
}
}
})
</script>

View file

@ -0,0 +1,197 @@
<script type="text/x-template" id="themes-github">
<div class="github-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
<h1 class="header-text">{{$root.getLz('settings.header.visual.theme.github.page')}}</h1>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="$root.openSettingsPage('styles')">
{{$root.getLz('settings.option.visual.theme.manageStyles')}}
</button>
</div>
<div class="col-auto flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="$root.checkForThemeUpdates()">
{{ $root.getLz('settings.option.visual.theme.checkForUpdates') }}
</button>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="installThemeURL()">
{{$root.getLz('settings.option.visual.theme.github.download')}}
</button>
</div>
</div>
</div>
<div class="gh-content">
<div class="repos-list">
<ul class="list-group list-group-flush">
<li @click="showRepo(repo)" class="list-group-item list-group-item-dark"
:style="{'background': (repo.id == openRepo.id) ? 'var(--keyColor)' : ''}"
v-for="repo in repos">
<div class="row">
<div class="col flex-center">
<div>
<h4 class="repo-name">{{ (repo.description != null) ? repo.description :
repo.full_name }}</h4>
<div>⭐ {{ repo.stargazers_count }}</div>
</div>
</div>
<div class="col-auto">
<span v-if="themesInstalled.includes(repo.full_name.toLowerCase())"
class="codicon codicon-cloud-download"></span>
</div>
</div>
</li>
</ul>
</div>
<div class="github-preview" v-if="openRepo.full_name">
<div class="gh-preview-header">
<div class="row nopadding">
<div class="col nopadding flex-center">
<div>
<h3 class="repo-preview-name">{{ openRepo.description }}</h3>
<div>
<div class="svg-icon inline"
:style="{'--url': 'url(\'./assets/github.svg\')'}"></div>
<a class="repo-url" target="_blank" :href="openRepo.html_url">{{ openRepo.full_name
}}</a></div>
<div>⭐ {{ openRepo.stargazers_count }}</div>
</div>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-primary" @click="installThemeRepo(openRepo)">
<span v-if="!themesInstalled.includes(openRepo.full_name.toLowerCase())">{{$root.getLz('action.install')}}</span>
<span v-else>{{$root.getLz('action.update')}}</span>
</button>
</div>
</div>
</div>
<hr>
<div v-html="openRepo.readme" class="github-content"></div>
</div>
<div class="github-preview" v-else>
</div>
</transition>
</div>
</div>
</script>
<script>
Vue.component('themes-github', {
template: "#themes-github",
props: [],
data: function () {
return {
repos: [],
openRepo: {
id: -1,
name: '',
description: '',
html_url: '',
stargazers_count: 0,
owner: {
avatar_url: ''
},
readme: ""
},
themesInstalled: [],
themes: []
}
},
mounted() {
this.themes = ipcRenderer.sendSync("get-themes")
this.getRepos();
this.getInstalledThemes();
},
methods: {
openThemesFolder() {
ipcRenderer.invoke("open-path", "themes")
},
getInstalledThemes() {
let self = this
const themes = ipcRenderer.sendSync("get-themes")
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
themes.forEach(theme => {
if (theme.github_repo !== "" && typeof theme.commit != "") {
self.themesInstalled.push(theme.github_repo.toLowerCase())
}
})
},
showRepo(repo) {
const self = this
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch(readmeUrl, requestOptions)
.then(response => response.text())
.then(result => {
self.openRepo = repo
self.openRepo.readme = self.convertReadMe(result);
})
.catch(error => {
self.openRepo = repo
self.openRepo.readme = `This repository doesn't have a README.md file.`;
console.log('error', error)
});
},
convertReadMe(text) {
return marked.parse(text)
},
installThemeRepo(repo) {
let self = this
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
repo: repo.full_name
});
app.confirm(msg, (res) => {
if (res) {
ipcRenderer.once("theme-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
self.getInstalledThemes()
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
}
});
ipcRenderer.invoke("get-github-theme", repo.html_url)
}
})
},
installThemeURL() {
let self = this
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
if (result) {
ipcRenderer.once("theme-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
}
});
ipcRenderer.invoke("get-github-theme", result)
}
});
},
getRepos() {
let self = this
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true&per_page=100", requestOptions)
.then(response => response.text())
.then(result => {
let items = JSON.parse(result).items
self.repos = items
})
.catch(error => console.log('error', error));
}
}
})
</script>

View file

@ -0,0 +1,367 @@
<script type="text/x-template" id="installed-themes">
<div class="installed-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
<h1 class="header-text">
{{ $root.getLz("settings.option.visual.theme.manageStyles") }}
</h1>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="$root.openSettingsPage('github-themes')">
{{$root.getLz('settings.option.visual.theme.github.explore')}}
</button>
</div>
<div class="col-auto flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="$root.checkForThemeUpdates()">
{{ $root.getLz('settings.option.visual.theme.checkForUpdates') }}
</button>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="openThemesFolder()">
{{$root.getLz('settings.option.visual.theme.github.openfolder')}}
</button>
</div>
</div>
</div>
<div class="gh-content">
<div class="repos-list">
<div class="repo-header">
<h4>{{$root.getLz('settings.option.visual.theme.github.available')}}</h4>
</div>
<ul class="list-group list-group-flush">
<template v-for="theme in themes">
<li @click="addStyle(theme.file)"
@contextmenu="contextMenu($event, theme)"
class="list-group-item list-group-item-dark"
:class="{'applied': $root.cfg.visual.styles.includes(theme.file)}">
<b-row>
<b-col class="themeLabel">{{theme.name}}</b-col>
<template v-if="$root.cfg.visual.styles.includes(theme.file)">
<b-col sm="auto" v-if="theme.pack">
<button class="themeContextMenu codicon codicon-package"></button>
</b-col>
<b-col sm="auto">
<button class="themeContextMenu codicon codicon-check"></button>
</b-col>
</template>
<template v-else>
<b-col sm="auto" v-if="theme.pack">
<button class="themeContextMenu codicon codicon-package"></button>
</b-col>
<b-col sm="auto">
<button @click.stop="contextMenu($event, theme)" class="themeContextMenu codicon codicon-list-unordered"></button>
</b-col>
</template>
</b-row>
</li>
<li @click="addStyle(packEntry.file)"
@contextmenu="contextMenu($event, theme)"
class="list-group-item list-group-item-dark addon"
v-for="packEntry in theme.pack"
:class="{'applied': $root.cfg.visual.styles.includes(packEntry.file)}"
v-if="theme.pack">
<b-row>
<b-col class="themeLabel">{{packEntry.name}}</b-col>
<template v-if="$root.cfg.visual.styles.includes(packEntry.file)">
<b-col sm="auto">
<button class="themeContextMenu codicon codicon-check"></button>
</b-col>
</template>
<template v-else>
<b-col sm="auto">
<button class="themeContextMenu codicon codicon-diff-added"></button>
</b-col>
</template>
</b-row>
</li>
</template>
</ul>
</div>
<div class="style-editor-container">
<div class="repo-header">
<h4>{{ $root.getLz("settings.option.visual.theme.github.applied") }} </h4>
</div>
<stylestack-editor ref="stackEditor" v-if="themes.length != 0" :themes="themes"/>
</div>
</div>
</div>
</script>
<script>
// do not translate
Vue.component('stylestack-editor', {
/*html*/
template: `
<div class="stylestack-editor" >
<draggable class="list-group" v-model="$root.cfg.visual.styles" @end="$root.reloadStyles()">
<b-list-group-item variant="dark" v-for="theme in $root.cfg.visual.styles" :key="theme">
<b-row>
<b-col sm="auto">
<div class="handle codicon codicon-grabber"></div>
</b-col>
<b-col class="themeLabel">{{getThemeName(theme)}}</b-col>
<b-col sm="auto">
<button class="removeItem codicon codicon-close" @click="remove(theme)"></button>
</b-col>
</b-row>
</b-list-group-item>
</draggable>
</div>
`,
props: {
themes: {
type: Array,
default: [],
required: true
}
},
data: function () {
return {
selected: null,
newTheme: null,
themeList: []
}
},
mounted() {
console.log(this.themes)
this.themeList = [...this.themes]
this.themeList.forEach(theme => {
if (theme.pack) {
theme.pack.forEach(packEntry => {
packEntry.file = theme.file.replace('index.less', '') + packEntry.file
this.themeList.push(packEntry)
})
}
})
},
methods: {
gitHubExplore() {
this.$root.openSettingsPage("github-themes")
},
getThemeName(filename) {
try {
return this.themeList.find(theme => theme.file === filename).name;
} catch (e) {
return filename;
}
},
moveUp() {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(this.selected)
if (index > 0) {
styles.splice(index, 1)
styles.splice(index - 1, 0, this.selected)
}
this.$root.reloadStyles()
},
moveDown() {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(this.selected)
if (index < styles.length - 1) {
styles.splice(index, 1)
styles.splice(index + 1, 0, this.selected)
}
this.$root.reloadStyles()
},
remove(style) {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(style)
styles.splice(index, 1)
this.$root.reloadStyles()
},
addStyle(style) {
const styles = this.$root.cfg.visual.styles
styles.push(style)
this.$root.reloadStyles()
}
}
})
</script>
<script>
Vue.component('installed-themes', {
template: "#installed-themes",
props: [],
data: function () {
return {
repos: [],
openRepo: {
id: -1,
name: '',
description: '',
html_url: '',
stargazers_count: 0,
owner: {
avatar_url: ''
},
readme: ""
},
themesInstalled: [],
themes: []
}
},
mounted() {
this.getThemesList();
},
methods: {
getThemesList() {
let self = this
let themes = ipcRenderer.sendSync("get-themes")
themes.unshift({
name: "Acrylic Grain",
file: "grain.less"
})
themes.unshift({
name: "Sweetener",
file: "sweetener.less"
})
themes.unshift({
name: "Reduce Visuals",
file: "reduce_visuals.less"
})
// themes.unshift({
// name: "Inline Drawer",
// file: "inline_drawer.less"
// })
themes.unshift({
name: "Dark",
file: "dark.less"
})
this.themes = themes
},
contextMenu(event, theme) {
let self = this
let menu = {
items: {
"uninstall": {
name: app.getLz("settings.option.visual.theme.uninstall"),
disabled: true,
action: () => {
app.confirm(app.stringTemplateParser(app.getLz("settings.prompt.visual.theme.uninstallTheme"), {
theme: theme.name ?? theme.file
}), (res) => {
if (res) {
console.debug(theme)
ipcRenderer.once("theme-uninstalled", (event, args) => {
console.debug(event, args)
self.getThemesList()
})
ipcRenderer.invoke("uninstall-theme", theme.path)
}
})
}
},
"viewInfo": {
name: app.getLz("settings.option.visual.theme.viewInfo"),
disabled: true,
action: () => {
}
}
}
}
if (theme.path) {
menu.items.uninstall.disabled = false
}
this.$root.showMenuPanel(menu, event)
},
openThemesFolder() {
ipcRenderer.invoke("open-path", "themes")
},
getInstalledThemes() {
let self = this
const themes = ipcRenderer.sendSync("get-themes")
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
themes.forEach(theme => {
if (theme.github_repo !== "" && typeof theme.commit != "") {
self.themesInstalled.push(theme.github_repo.toLowerCase())
}
})
},
addStyle(filename) {
this.$refs.stackEditor.addStyle(filename)
},
showRepo(repo) {
const self = this
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch(readmeUrl, requestOptions)
.then(response => response.text())
.then(result => {
self.openRepo = repo
self.openRepo.readme = self.convertReadMe(result);
})
.catch(error => {
self.openRepo = repo
self.openRepo.readme = `This repository doesn't have a README.md file.`;
console.log('error', error)
});
},
convertReadMe(text) {
return marked.parse(text)
},
installThemeRepo(repo) {
let self = this
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
repo: repo.full_name
});
app.confirm(msg, (res) => {
if (res) {
ipcRenderer.once("theme-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
self.getInstalledThemes()
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
}
});
ipcRenderer.invoke("get-github-theme", repo.html_url)
}
})
},
installThemeURL() {
let self = this
app.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
if (result) {
ipcRenderer.once("theme-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
}
});
ipcRenderer.invoke("get-github-theme", result)
}
});
},
getRepos() {
let self = this
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
.then(response => response.text())
.then(result => {
let items = JSON.parse(result).items
self.repos = items
})
.catch(error => console.log('error', error));
}
}
})
</script>

File diff suppressed because it is too large Load diff

View file

@ -145,7 +145,7 @@
Local Library
</div>
<template v-if="!$root.cfg.general.sidebarCollapsed.localLibrary">
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}">
<sidebar-playlist :item="{attributes: { name:'Songs'} , id:'ciderlocal'}"></sidebar-playlist>
</template>
</template>
<template v-if="$root.getPlaylistFolderChildren('p.applemusic').length != 0">

View file

@ -86,13 +86,13 @@
</transition>
<transition name="fsModeSwitch">
<div class="fullscreen-view-container" v-if="appMode == 'fullscreen'">
<fullscreen-view :image="currentArtUrlRaw" :time="lyriccurrenttime" :lyrics="lyrics"
<fullscreen-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics"
:richlyrics="richlyrics"></fullscreen-view>
</div>
</transition>
<transition name="fsModeSwitch">
<div class="fullscreen-view-container" v-if="appMode == 'mini'">
<mini-view :image="currentArtUrlRaw" :time="lyriccurrenttime" :lyrics="lyrics" :richlyrics="richlyrics">
<mini-view :image="currentArtUrlRaw" :time="mk.currentPlaybackTime - lyricOffset" :lyrics="lyrics" :richlyrics="richlyrics">
</mini-view>
</div>
</transition>

View file

@ -25,17 +25,22 @@
<div class="row">
<div class="col">
<h3>{{$root.getLz('term.ciderTeam')}}</h3>
<button class="md-btn teamBtn" @click="window.open(member.link)" v-for="member in team">
<div class="md-btn teamBtn" v-for="member in team" @click="window.open(member.link)">
<img :src="member.avatar"/>
<div class="row" style="width:100%;">
<div class="col" style="text-align: left">
<div class="col" style="text-align: left;">
{{ member.name }}
</div>
<div class="col" style="text-align: right">
<button @click.stop="window.open(member.twitter)" class="social-btn" v-if="member.twitter">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="white" style=""><path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"></path></svg>
</button>
</div>
<div class="col-auto">
<b>{{ member.role }}</b>
</div>
</div>
</button>
</div>
</div>
</div>
</div>
@ -64,25 +69,29 @@
name: 'cryptofyre',
link: 'https://github.com/cryptofyre',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4'
avatar: 'https://avatars.githubusercontent.com/u/33162551?v=4',
twitter: 'https://twitter.com/cryptofyre'
},
{
name: 'Core',
link: 'https://github.com/coredev-uk',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4'
avatar: 'https://avatars.githubusercontent.com/u/64542347?v=4',
twitter: 'https://twitter.com/core_hdd'
},
{
name: 'Quacksire',
link: 'https://github.com/quacksire',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4'
avatar: 'https://avatars.githubusercontent.com/u/19170969?v=4',
twitter: 'https://twitter.com/duckdoquack'
},
{
name: 'booploops',
link: 'https://github.com/booploops',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4'
avatar: 'https://avatars.githubusercontent.com/u/49113086?v=4',
twitter: 'https://twitter.com/boopl00ps'
},
{
name: 'vapormusic',
@ -94,25 +103,29 @@
name: 'crypticplank',
link: 'https://github.com/crypticplank',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4'
avatar: 'https://avatars.githubusercontent.com/u/52553007?v=4',
twitter: 'https://twitter.com/crypticplank'
},
{
name: 'Maikiwi',
link: 'https://github.com/maikirakiwi',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4'
avatar: 'https://avatars.githubusercontent.com/u/74925636?v=4',
twitter: 'https://twitter.com/notmaikiwi'
},
{
name: 'yazninja',
link: 'https://github.com/yazninja',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/71800112?v=4'
avatar: 'https://avatars.githubusercontent.com/u/71800112?v=4',
twitter: 'https://twitter.com/YazNinjaa'
},
{
name: 'GamingLiamStudios',
link: 'https://github.com/GamingLiamStudios',
role: app.getLz('term.developer'),
avatar: 'https://avatars.githubusercontent.com/u/58615717?v=4'
avatar: 'https://avatars.githubusercontent.com/u/58615717?v=4',
twitter: 'https://twitter.com/GLStudios_'
},
{
name: 'Amaru',

View file

@ -527,7 +527,7 @@
if (this.data.type.includes('albums')) {
let date = this.data.attributes.releaseDate;
if (date == null || date === "") return "";
return `${this.data.relationships.tracks.data[0].attributes.genreNames[0]} · ${new Date(date).getFullYear()}`
return `${this.data.attributes.genreNames[0]} · ${new Date(date).getFullYear()}`
}
},
async isInLibrary() {

View file

@ -1,5 +1,7 @@
<script type="text/x-template" id="installed-themes">
<div class="content-inner github-themes-page installed-themes-page">
//Not used for Now
<!-- <script type="text/x-template" id="installed-themes">
<div class="installed-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
@ -22,7 +24,6 @@
{{$root.getLz('settings.option.visual.theme.github.openfolder')}}
</button>
</div>
</div>
</div>
<div class="gh-content">
@ -365,4 +366,4 @@
}
}
})
</script>
</script> -->

View file

@ -1,13 +1,13 @@
<script type="text/x-template" id="cider-recentlyadded">
<div class="content-inner">
<h1 class="header-text">{{$root.getLz('term.recentlyAdded')}}</h1>
<div class="well itemContainer" v-if="itemSize == 'normal'">
<div class="well itemContainer collection-list-square" v-if="itemSize == 'normal'">
<mediaitem-square v-for="item in items" :item="item"></mediaitem-square>
</div>
<div class="well itemContainer" v-else="itemSize == 'compact'">
<div class="well itemContainer collection-list-square" v-else="itemSize == 'compact'">
<mediaitem-list-item :show-meta-data="true" :show-library-status="false" v-for="item in items" :item="item"></mediaitem-list-item>
</div>
<div class="well itemContainer" v-show="loading">
<div class="well itemContainer collection-list-square" v-show="loading">
<div class="spinner"></div>
</div>
<button v-if="nextUrl && !loading" style="opacity:0;height: 32px;" v-observe-visibility="{callback: visibilityChanged}">{{$root.getLz('term.showMore')}}

View file

@ -1,5 +1,7 @@
<script type="text/x-template" id="plugins-github">
<div class="content-inner github-themes-page">
//Not used for Now
<!-- <script type="text/x-template" id="plugins-github">
<div class="github-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
@ -186,3 +188,4 @@
}
})
</script>
-->

View file

@ -613,29 +613,27 @@
<div class="md-option-header">
<span>{{$root.getLz('settings.header.lyrics')}}</span>
</div>
<div class="settings-option-body">
<div style="opacity: 0.5; pointer-events: none;">
<div class="md-option-line">
<div class="md-option-segment">
{{$root.getLz('settings.option.lyrics.enableMusixmatch')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" switch checked/>
</label>
<!-- <input type="checkbox" v-model="app.cfg.lyrics.enable_mxm" switch /> -->
</div>
</div>
</div>
<div class="settings-option-body">
<div class="md-option-line">
<!-- <div class="md-option-line" v-if="app.cfg.lyrics.enable_mxm"> -->
<div class="md-option-segment">
{{$root.getLz('settings.option.lyrics.enableMusixmatchKaraoke')}}
{{$root.getLz('settings.option.lyrics.enableMusixmatch')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.lyrics.mxm_karaoke" switch/>
</label>
<input type="checkbox" v-model="app.cfg.lyrics.enable_mxm" switch />
</label>
</div>
</div>
<div class="md-option-line">
<div class="md-option-line" v-if="app.cfg.lyrics.enable_mxm">
<div class="md-option-segment">
{{$root.getLz('settings.option.lyrics.enableMusixmatchKaraoke')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.lyrics.mxm_karaoke" switch/>
</label>
</div>
</div>
</div>
<div class="md-option-line">
@ -646,271 +644,66 @@
<label>
<select class="md-select" v-model="app.cfg.lyrics.mxm_language">
<option value='disabled'>Disabled</option>
<option value='ab'>Abkhazian</option>
<option value='aa'>Afar</option>
<option value='af'>Afrikaans</option>
<option value='ak'>Akan</option>
<option value='sq'>Albanian</option>
<option value='am'>Amharic</option>
<option value='ar'>Arabic</option>
<option value='an'>Aragonese</option>
<option value='hy'>Armenian</option>
<option value='as'>Assamese</option>
<option value='a5'>Assamese-romaji</option>
<option value='a3'>Asturian</option>
<option value='av'>Avaric</option>
<option value='ae'>Avestan</option>
<option value='ay'>Aymara</option>
<option value='az'>Azerbaijani</option>
<option value='bm'>Bambara</option>
<option value='ba'>Bashkir</option>
<option value='eu'>Basque</option>
<option value='b1'>Bavarian</option>
<option value='be'>Belarusian</option>
<option value='bn'>Bengali</option>
<option value='b5'>Bengali-romaji</option>
<option value='bh'>Bihari languages</option>
<option value='b3'>Bishnupriya</option>
<option value='bi'>Bislama</option>
<option value='bs'>Bosnian</option>
<option value='br'>Breton</option>
<option value='bg'>Bulgarian</option>
<option value='my'>Burmese</option>
<option value='ca'>Catalan</option>
<option value='c2'>Cebuano</option>
<option value='b2'>Central bikol</option>
<option value='c3'>Central kurdish</option>
<option value='ch'>Chamorro</option>
<option value='c1'>Chavacano</option>
<option value='ce'>Chechen</option>
<option value='ny'>Chichewa</option>
<option value='zh'>Chinese (simplified)</option>
<option value='z1'>Chinese (traditional)</option>
<option value='rz'>Chinese-romaji</option>
<option value='cu'>Church slavic</option>
<option value='cv'>Chuvash</option>
<option value='kw'>Cornish</option>
<option value='co'>Corsican</option>
<option value='cr'>Cree</option>
<option value='c4'>Creoles and pidgins</option>
<option value='c5'>Creoles and pidgins, english based</option>
<option value='c6'>Creoles and pidgins, french-based</option>
<option value='c7'>Creoles and pidgins, portuguese-based</option>
<option value='hr'>Croatian</option>
<option value='cs'>Czech</option>
<option value='da'>Danish</option>
<option value='d1'>Dimli (individual language)</option>
<option value='dv'>Divehi</option>
<option value='d3'>Dotyali</option>
<option value='nl'>Dutch</option>
<option value='dz'>Dzongkha</option>
<option value='m2'>Eastern mari</option>
<option value='a2'>Egyptian arabic</option>
<option value='e1'>Emilian-romagnol</option>
<option value='en'>English</option>
<option value='m6'>Erzya</option>
<option value='eo'>Esperanto</option>
<option value='et'>Estonian</option>
<option value='ee'>Ewe</option>
<option value='fo'>Faroese</option>
<option value='h1'>Fiji hindi</option>
<option value='fj'>Fijian</option>
<option value='f1'>Filipino</option>
<option value='fi'>Finnish</option>
<option value='fr'>French</option>
<option value='f2'>Frisian, northern</option>
<option value='fy'>Frisian, western</option>
<option value='ff'>Fulah</option>
<option value='gl'>Galician</option>
<option value='lg'>Ganda</option>
<option value='ka'>Georgian</option>
<option value='de'>German</option>
<option value='n2'>German, low</option>
<option value='g1'>Goan konkani</option>
<option value='el'>Greek</option>
<option value='e2'>Greek-romaji</option>
<option value='kl'>Greenlandic</option>
<option value='gn'>Guarani</option>
<option value='gu'>Gujarati</option>
<option value='g2'>Gujarati-romaji</option>
<option value='ht'>Haitian creole</option>
<option value='ha'>Hausa</option>
<option value='he'>Hebrew</option>
<option value='hz'>Herero</option>
<option value='hi'>Hindi</option>
<option value='h3'>Hindi-romaji</option>
<option value='ho'>Hiri motu</option>
<option value='hu'>Hungarian</option>
<option value='is'>Icelandic</option>
<option value='io'>Ido</option>
<option value='ig'>Igbo</option>
<option value='i1'>Iloko</option>
<option value='id'>Indonesian</option>
<option value='ia'>Interlingua</option>
<option value='ie'>Interlingue</option>
<option value='iu'>Inuktitut</option>
<option value='ik'>Inupiaq</option>
<option value='ga'>Irish</option>
<option value='it'>Italian</option>
<option value='ja'>Japanese</option>
<option value='rj'>Japanese-romaji</option>
<option value='jv'>Javanese</option>
<option value='x1'>Kalmyk</option>
<option value='kn'>Kannada</option>
<option value='k2'>Kannada-romaji</option>
<option value='kr'>Kanuri</option>
<option value='k1'>Karachay-balkar</option>
<option value='ks'>Kashmiri</option>
<option value='kk'>Kazakh</option>
<option value='km'>Khmer, central</option>
<option value='ki'>Kikuyu</option>
<option value='rw'>Kinyarwanda</option>
<option value='ky'>Kirghiz</option>
<option value='kv'>Komi</option>
<option value='kg'>Kongo</option>
<option value='ko'>Korean</option>
<option value='rk'>Korean-romaji</option>
<option value='kj'>Kuanyama</option>
<option value='ku'>Kurdish</option>
<option value='lo'>Lao</option>
<option value='la'>Latin</option>
<option value='lv'>Latvian</option>
<option value='l1'>Lezghian</option>
<option value='li'>Limburgish</option>
<option value='ln'>Lingala</option>
<option value='lt'>Lithuanian</option>
<option value='j1'>Lojban</option>
<option value='l2'>Lombard</option>
<option value='lu'>Luba-katanga</option>
<option value='lb'>Luxembourgish</option>
<option value='mk'>Macedonian</option>
<option value='m1'>Maithili</option>
<option value='mg'>Malagasy</option>
<option value='ms'>Malay</option>
<option value='ml'>Malayalam</option>
<option value='m8'>Malayalam-romaji</option>
<option value='mt'>Maltese</option>
<option value='gv'>Manx</option>
<option value='mi'>Maori</option>
<option value='mr'>Marathi</option>
<option value='m9'>Marathi-romaji</option>
<option value='mh'>Marshallese</option>
<option value='m7'>Mazanderani</option>
<option value='m3'>Minangkabau</option>
<option value='x2'>Mingrelian</option>
<option value='m5'>Mirandese</option>
<option value='mo'>Moldavian</option>
<option value='mn'>Mongolian</option>
<option value='n4'>Nahuatl</option>
<option value='na'>Nauru</option>
<option value='nv'>Navajo</option>
<option value='nd'>Ndebele, north</option>
<option value='nr'>Ndebele, south</option>
<option value='ng'>Ndonga</option>
<option value='n1'>Neapolitan</option>
<option value='n3'>Nepal bhasa</option>
<option value='ne'>Nepali</option>
<option value='n5'>Nepali-romaji</option>
<option value='l3'>Northern luri</option>
<option value='no'>Norwegian</option>
<option value='nb'>Norwegian bokmål</option>
<option value='nn'>Norwegian nynorsk</option>
<option value='oc'>Occitan</option>
<option value='oj'>Ojibwa</option>
<option value='or'>Oriya</option>
<option value='o1'>Oriya-romaji</option>
<option value='om'>Oromo</option>
<option value='os'>Ossetian</option>
<option value='pi'>Pali</option>
<option value='p1'>Pampanga</option>
<option value='pa'>Panjabi</option>
<option value='p5'>Panjabi-romaji</option>
<option value='fa'>Persian</option>
<option value='p2'>Pfaelzisch</option>
<option value='p3'>Piemontese</option>
<option value='pl'>Polish</option>
<option value='pt'>Portuguese</option>
<option value='ps'>Pushto</option>
<option value='qu'>Quechua</option>
<option value='ro'>Romanian</option>
<option value='rm'>Romansh</option>
<option value='rn'>Rundi</option>
<option value='b4'>Russia buriat</option>
<option value='ru'>Russian</option>
<option value='r2'>Russian-romaji</option>
<option value='r1'>Rusyn</option>
<option value='se'>Sami, northern</option>
<option value='sm'>Samoan</option>
<option value='sg'>Sango</option>
<option value='sa'>Sanskrit</option>
<option value='s4'>Sanskrit-romaji</option>
<option value='sc'>Sardinian</option>
<option value='s3'>Scots</option>
<option value='gd'>Scottish gaelic</option>
<option value='sr'>Serbian</option>
<option value='sh'>Serbo-croatian</option>
<option value='sn'>Shona</option>
<option value='ii'>Sichuan yi</option>
<option value='s2'>Sicilian</option>
<option value='sd'>Sindhi</option>
<option value='si'>Sinhala</option>
<option value='sk'>Slovak</option>
<option value='sl'>Slovenian</option>
<option value='so'>Somali</option>
<option value='d2'>Sorbian, lower</option>
<option value='h2'>Sorbian, upper</option>
<option value='st'>Sotho, southern</option>
<option value='a4'>South azerbaijani</option>
<option value='es'>Spanish</option>
<option value='su'>Sundanese</option>
<option value='sw'>Swahili</option>
<option value='ss'>Swati</option>
<option value='sv'>Swedish</option>
<option value='tl'>Tagalog</option>
<option value='ty'>Tahitian</option>
<option value='tg'>Tajik</option>
<option value='ta'>Tamil</option>
<option value='t2'>Tamil-romaji</option>
<option value='tt'>Tatar</option>
<option value='te'>Telugu</option>
<option value='t3'>Telugu-romaji</option>
<option value='th'>Thai</option>
<option value='t4'>Thai-romaji</option>
<option value='bo'>Tibetan</option>
<option value='ti'>Tigrinya</option>
<option value='to'>Tonga (tonga islands)</option>
<option value='a1'>Tosk albanian</option>
<option value='ts'>Tsonga</option>
<option value='tn'>Tswana</option>
<option value='tr'>Turkish</option>
<option value='tk'>Turkmen</option>
<option value='t1'>Tuvinian</option>
<option value='tw'>Twi</option>
<option value='ug'>Uighur</option>
<option value='uk'>Ukrainian</option>
<option value='ur'>Urdu</option>
<option value='u1'>Urdu-romaji</option>
<option value='uz'>Uzbek</option>
<option value='ve'>Venda</option>
<option value='v1'>Venetian</option>
<option value='v2'>Veps</option>
<option value='vi'>Vietnamese</option>
<option value='v3'>Vlaams</option>
<option value='vo'>Volapük</option>
<option value='wa'>Walloon</option>
<option value='w1'>Waray</option>
<option value='cy'>Welsh</option>
<option value='m4'>Western mari</option>
<option value='p4'>Western panjabi</option>
<option value='wo'>Wolof</option>
<option value='w2'>Wu chinese</option>
<option value='xh'>Xhosa</option>
<option value='s1'>Yakut</option>
<option value='yi'>Yiddish</option>
<option value='yo'>Yoruba</option>
<option value='y1'>Yue chinese</option>
<option value='za'>Zhuang</option>
<option value='zu'>Zulu</option>
<option value='afrikaans'>Afrikaans</option>
<option value='albanian'>Albanian</option>
<option value='arab'>Arabic</option>
<option value='armenian'>Armenian</option>
<option value='azerbaijani'>Azerbaijani</option>
<option value='bengali'>Bengali</option>
<option value='bosnian'>Bosnian</option>
<option value='bulgarian'>Bulgarian</option>
<option value='simplified chinese'>Chinese (Simplified)</option>
<option value='traditional chinese'>Chinese (Traditional)</option>
<option value='croatian'>Croatian</option>
<option value='czech'>Czech</option>
<option value='danish'>Danish</option>
<option value='estonian'>Estonian</option>
<option value='english'>English</option>
<option value='farsi'>Farsi</option>
<option value='filipino'>Filipino</option>
<option value='french'>French</option>
<option value='georgian'>Georgian</option>
<option value='german'>German</option>
<option value='greek'>Greek</option>
<option value='gujarati'>Gujarati</option>
<option value='haitian-creole'>Haitian-Creole</option>
<option value='hebrew'>Hebrew</option>
<option value='hindi'>Hindi</option>
<option value='hungarian'>Hungarian</option>
<option value='icelandic'>Icelandic</option>
<option value='italian'>Italian</option>
<option value='japanese'>Japanese</option>
<option value='japanese-romaji'>Romanized Japanese</option>
<option value='kannada'>Kannada</option>
<option value='kazakh'>Kazakh</option>
<option value='korean-romaji'>Romanized Korean</option>
<option value='lao'>Lao</option>
<option value='latvian'>Latvian</option>
<option value='lithuanian'>Lithuanian</option>
<option value='macedonian'>Macedonian</option>
<option value='malay'>Malay</option>
<option value='malayalam'>Malayalam</option>
<option value='mongolian'>Mongolian</option>
<option value='nepali'>Nepali</option>
<option value='norwegian'>Norwegian</option>
<option value='panjabi'>Panjabi</option>
<option value='polish'>Polish</option>
<option value='portuguese'>Portuguese</option>
<option value='romanian'>Romanian</option>
<option value='russian'>Russian</option>
<option value='serbian'>Serbian</option>
<option value='slovak'>Slovak</option>
<option value='slovenian'>Slovenian</option>
<option value='spanish'>Spanish</option>
<option value='suomi'>Suomi</option>
<option value='swedish'>Swedish</option>
<option value='tamil'>Tamil</option>
<option value='telugu'>Telugu</option>
<option value='turkish'>Turkish</option>
<option value='ukrainian'>Ukrainian</option>
<option value='urdu'>Urdu</option>
<option value='uzbek'>Uzbek</option>
<option value='vietnamese'>Vietnamese</option>
</select>
</label>
</div>

View file

@ -1,5 +1,7 @@
<script type="text/x-template" id="themes-github">
<div class="content-inner github-themes-page">
//Not used for Now
<!-- <script type="text/x-template" id="themes-github">
<div class="github-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
@ -195,3 +197,4 @@
}
})
</script>
-->

View file

@ -279,6 +279,12 @@ input[type=range].md-slider::-webkit-slider-runnable-track {
width: auto;
}
@media only screen and (min-width: 1133px) and (max-width: 1241px) {
.row .col-auto {
display: none !important;
}
}
.col-1 {
flex: 0 0 auto;
width: 8.33333333%;