├── src ├── assets │ ├── .gitkeep │ ├── not_found.webp │ ├── icons │ │ ├── turtle-72x72.png │ │ ├── turtle-96x96.png │ │ ├── turtle-128x128.png │ │ ├── turtle-144x144.png │ │ ├── turtle-152x152.png │ │ ├── turtle-192x192.png │ │ ├── turtle-384x384.png │ │ └── turtle-512x512.png │ ├── microsoft.svg │ ├── chunithm.svg │ ├── github.svg │ ├── mai2.svg │ ├── ongeki.svg │ └── gitlab.svg ├── app │ ├── admin │ │ ├── admin.component.css │ │ └── admin.component.spec.ts │ ├── message │ │ ├── message.component.css │ │ ├── message.component.html │ │ ├── message.module.ts │ │ ├── message.component.ts │ │ └── message.component.spec.ts │ ├── oauth-callback │ │ ├── oauth-callback.component.css │ │ ├── oauth-callback.component.html │ │ └── oauth-callback.component.spec.ts │ ├── announcements │ │ ├── announcements.component.css │ │ ├── announcement │ │ │ ├── announcement.component.css │ │ │ ├── announcement.component.html │ │ │ └── announcement.component.spec.ts │ │ ├── edit │ │ │ ├── edit.component.css │ │ │ └── edit.component.spec.ts │ │ └── announcements.component.spec.ts │ ├── sega │ │ ├── chunithm │ │ │ └── v2 │ │ │ │ ├── v2-profile │ │ │ │ ├── v2-profile.component.css │ │ │ │ └── v2-profile.component.spec.ts │ │ │ │ ├── model │ │ │ │ ├── ChusanFrame.ts │ │ │ │ ├── ChusanMapIcon.ts │ │ │ │ ├── ChusanTrophy.ts │ │ │ │ ├── ChusanNamePlate.ts │ │ │ │ ├── ChusanSystemVoice.ts │ │ │ │ ├── ChusanAvatarAcc.ts │ │ │ │ ├── V2PcRanking.ts │ │ │ │ ├── V2Item.ts │ │ │ │ ├── V2SymbolChat.ts │ │ │ │ ├── V2UserRanking.ts │ │ │ │ ├── ChusanSymbolChat.ts │ │ │ │ ├── ChusanCharacter.ts │ │ │ │ ├── V2Character.ts │ │ │ │ ├── V2Record.ts │ │ │ │ ├── ChusanRival.ts │ │ │ │ ├── ChusanMusic.ts │ │ │ │ ├── V2PlayLog.ts │ │ │ │ └── V2Profile.ts │ │ │ │ ├── util │ │ │ │ ├── to-rank.pipe.spec.ts │ │ │ │ ├── to-rating.pipe.spec.ts │ │ │ │ ├── to-tech-rating.pipe.spec.ts │ │ │ │ ├── to-level-string.pipe.spec.ts │ │ │ │ ├── character-image.pipe.spec.ts │ │ │ │ ├── cource-id-to-class.pipe.spec.ts │ │ │ │ ├── to-rating.pipe.ts │ │ │ │ ├── to-level-string.pipe.ts │ │ │ │ ├── character-image.pipe.ts │ │ │ │ ├── release-tag.service.spec.ts │ │ │ │ ├── cource-id-to-class.pipe.ts │ │ │ │ ├── rating-class.pipe.ts │ │ │ │ ├── to-rank.pipe.ts │ │ │ │ ├── to-tech-rating.pipe.ts │ │ │ │ └── release-tag.service.ts │ │ │ │ ├── v2-setting │ │ │ │ ├── v2-name-setting │ │ │ │ │ ├── v2-name-setting.scss │ │ │ │ │ ├── v2-name-setting.html │ │ │ │ │ └── v2-name-setting.dialog.ts │ │ │ │ ├── v2-setting.component.css │ │ │ │ ├── v2-version-setting │ │ │ │ │ ├── v2-version-setting.dialog.ts │ │ │ │ │ └── v2-version-setting.html │ │ │ │ └── v2-setting.component.spec.ts │ │ │ │ ├── v2-rival-list │ │ │ │ ├── v2-rival-list.component.css │ │ │ │ └── v2-rival-list.component.spec.ts │ │ │ │ ├── v2-userbox │ │ │ │ ├── v2-userbox-setting │ │ │ │ │ └── v2-userbox.setting.css │ │ │ │ ├── v2-symbol-chat-setting │ │ │ │ │ ├── v2-symbol-chat-setting.component.spec.ts │ │ │ │ │ └── v2-symbol-chat-setting.component.css │ │ │ │ └── v2-userbox.component.spec.ts │ │ │ │ ├── v2-user-ranking │ │ │ │ ├── v2-user-ranking.component.scss │ │ │ │ └── v2-user-ranking.component.spec.ts │ │ │ │ ├── v2-song-score-ranking │ │ │ │ ├── v2-song-score-ranking.component.spec.ts │ │ │ │ └── v2-song-score-ranking.component.scss │ │ │ │ ├── v2-rating │ │ │ │ ├── v2-rating.component.spec.ts │ │ │ │ └── v2-rating.component.scss │ │ │ │ ├── v2-recent │ │ │ │ └── v2-recent.component.spec.ts │ │ │ │ ├── v2-songlist │ │ │ │ └── v2-songlist.component.spec.ts │ │ │ │ ├── v2-character │ │ │ │ ├── v2-character.component.spec.ts │ │ │ │ └── v2-character.component.scss │ │ │ │ ├── chuni-music-db.service.ts │ │ │ │ └── v2.routing.ts │ │ ├── maimai2 │ │ │ ├── maimai2-profile │ │ │ │ ├── maimai2-profile.component.css │ │ │ │ ├── maimai2-profile.component.spec.ts │ │ │ │ └── maimai2-profile.component.ts │ │ │ ├── maimai2-setting │ │ │ │ ├── maimai2-setting.component.css │ │ │ │ ├── maimai2-upload-user-portrait │ │ │ │ │ ├── maimai2-upload-user-portrait.dialog.css │ │ │ │ │ └── maimai2-upload-user-portrait.dialog.html │ │ │ │ └── maimai2-setting.component.spec.ts │ │ │ ├── maimai2-songlist │ │ │ │ ├── maimai2-songlist.component.css │ │ │ │ └── maimai2-songlist.component.spec.ts │ │ │ ├── model │ │ │ │ ├── Maimai2UserCircleData.ts │ │ │ │ ├── Maimai2FestaSideData.ts │ │ │ │ ├── Maimai2DxPass.ts │ │ │ │ ├── Maimai2Photo.ts │ │ │ │ ├── Maimai2CircleFestaRankInfo.ts │ │ │ │ ├── Maimai2RequestJoinCircleUser.ts │ │ │ │ ├── Maimai2UserCirclePointData.ts │ │ │ │ ├── Maimai2UserCirclePointRankingResult.ts │ │ │ │ ├── Maimai2Rival.ts │ │ │ │ ├── Maimai2CircleFestaData.ts │ │ │ │ ├── Maimai2GameResultFestaData.ts │ │ │ │ ├── Maimai2Circle.ts │ │ │ │ ├── Maimai2GameFestaData.ts │ │ │ │ ├── Maimai2CircleMemberInfo.ts │ │ │ │ ├── Maimai2GameFestaInfo.ts │ │ │ │ ├── Maimai2UserFestaInfo.ts │ │ │ │ ├── Maimai2UserResultFestaData.ts │ │ │ │ ├── Maimai2UserCircleInfo.ts │ │ │ │ ├── Maimai2UserFestaData.ts │ │ │ │ ├── Maimai2Music.ts │ │ │ │ ├── Maimai2GameFesta.ts │ │ │ │ ├── Maimai2Enums.ts │ │ │ │ └── Maimai2Profile.ts │ │ │ ├── maimai2-rival │ │ │ │ ├── maimai2-rival.component.css │ │ │ │ └── maimai2-rival.component.spec.ts │ │ │ ├── maimai2-photos │ │ │ │ └── maimai2-photos.component.scss │ │ │ ├── maimai2-festa │ │ │ │ └── maimai2-festa.component.spec.ts │ │ │ ├── maimai2-circle │ │ │ │ └── maimai2-circle.component.spec.ts │ │ │ ├── maimai2-dxpass │ │ │ │ ├── maimai2-dxpass.component.spec.ts │ │ │ │ └── maimai2-dxpass.component.css │ │ │ ├── maimai2-song-detail │ │ │ │ └── maimai2-song-detail.component.spec.ts │ │ │ └── maimai2-rating │ │ │ │ └── maimai2-rating.component.scss │ │ └── ongeki │ │ │ ├── ongeki-music-ranking │ │ │ ├── ongeki-music-ranking.component.scss │ │ │ ├── ongeki-music-ranking.component.spec.ts │ │ │ └── ongeki-music-ranking.component.ts │ │ │ ├── ongeki-user-ranking │ │ │ ├── ongeki-user-ranking.component.scss │ │ │ └── ongeki-user-ranking.component.spec.ts │ │ │ ├── model │ │ │ ├── OngekiPcRanking.ts │ │ │ ├── OngekiTrophy.ts │ │ │ ├── OngekiSkill.ts │ │ │ ├── OngekiCharacter.ts │ │ │ ├── OngekiUserRanking.ts │ │ │ ├── OngekiGameRanking.ts │ │ │ ├── OngekiRival.ts │ │ │ ├── OngekiMusic.ts │ │ │ ├── PlayerRatingItem.ts │ │ │ ├── PlayerNewRatingItem.ts │ │ │ ├── OngekiCard.ts │ │ │ ├── PlayerCard.ts │ │ │ ├── OngekiEnums.ts │ │ │ └── OngekiProfile.ts │ │ │ ├── ongeki-setting │ │ │ ├── ongeki-setting.component.css │ │ │ └── ongeki-setting.component.spec.ts │ │ │ ├── util │ │ │ ├── to-tech-rating.pipe.spec.ts │ │ │ ├── to-tech-sprite.pipe.spec.ts │ │ │ ├── to-battle-sprite.pipe.spec.ts │ │ │ ├── to-level-decimal.pipe.spec.ts │ │ │ ├── to-rarity-sprite.pipe.spec.ts │ │ │ ├── to-attribute-class.pipe.spec.ts │ │ │ ├── to-tech-honor-sprite.pipe.spec.ts │ │ │ ├── to-rarity-sprite.pipe.ts │ │ │ ├── to-level-decimal.pipe.ts │ │ │ ├── to-attribute-class.pipe.ts │ │ │ ├── to-tech-sprite.pipe.ts │ │ │ ├── to-battle-sprite.pipe.ts │ │ │ ├── to-tech-honor-sprite.pipe.ts │ │ │ └── to-tech-rating.pipe.ts │ │ │ ├── ongeki-card │ │ │ ├── ongeki-card.component.css │ │ │ └── ongeki-card.component.spec.ts │ │ │ ├── ongeki-rival-list │ │ │ ├── ongeki-rival-list.component.css │ │ │ └── ongeki-rival-list.component.spec.ts │ │ │ ├── ongeki-card-level │ │ │ ├── ongeki-card-level.component.css │ │ │ ├── ongeki-card-level.component.ts │ │ │ ├── ongeki-card-level.component.spec.ts │ │ │ └── ongeki-card-level.component.html │ │ │ ├── new-rating.service.spec.ts │ │ │ ├── ongeki-card-item │ │ │ └── ongeki-card-item.component.spec.ts │ │ │ ├── ongeki-recent-item │ │ │ ├── ongeki-recent-item.component.spec.ts │ │ │ └── ongeki-recent-item.component.ts │ │ │ ├── ongeki-song-score-ranking │ │ │ └── ongeki-song-score-ranking.component.spec.ts │ │ │ ├── ongeki-rating │ │ │ ├── ongeki-rating.component.spec.ts │ │ │ └── ongeki-rating.component.css │ │ │ ├── ongeki-recent │ │ │ └── ongeki-recent.component.spec.ts │ │ │ ├── ongeki-profile │ │ │ └── ongeki-profile.component.spec.ts │ │ │ ├── ongeki-song-list │ │ │ ├── ongeki-song-list.component.spec.ts │ │ │ └── ongeki-song-list.component.css │ │ │ ├── ongeki-card-gallery │ │ │ ├── ongeki-card-gallery.component.spec.ts │ │ │ └── ongeki-card-gallery.component.css │ │ │ └── ongeki-battle-point │ │ │ ├── ongeki-battle-point.component.spec.ts │ │ │ └── ongeki-battle-point.component.css │ ├── cards │ │ ├── cards.component.css │ │ └── cards.component.spec.ts │ ├── password-reset │ │ ├── password-reset.component.css │ │ └── password-reset.component.spec.ts │ ├── model │ │ ├── PropertyEntry.ts │ │ ├── Page.ts │ │ └── ApiResponse.ts │ ├── sign-in │ │ ├── sign-in.component.css │ │ └── sign-in.component.spec.ts │ ├── util │ │ ├── tsconfig.json │ │ ├── ordinal.pipe.spec.ts │ │ ├── to-date.pipe.spec.ts │ │ ├── to-date.pipe.ts │ │ ├── array-utils.ts │ │ ├── formatnumber.pipe.spec.ts │ │ ├── full-width.pipe.spec.ts │ │ ├── to-date.pipe.js.map │ │ ├── formatnumber.pipe.ts │ │ ├── tools.module.js.map │ │ ├── debounce.ts │ │ ├── array-utils.js.map │ │ ├── full-width.pipe.ts │ │ ├── formatnumber.pipe.js.map │ │ ├── array-utils.js │ │ ├── tools.module.ts │ │ ├── full-width.pipe.js.map │ │ └── ordinal.pipe.ts │ ├── sign-up │ │ ├── sign-up.component.css │ │ └── sign-up.component.spec.ts │ ├── keychip │ │ ├── keychip.component.css │ │ └── keychip.component.spec.ts │ ├── database │ │ └── preload.service.spec.ts │ ├── menu.service.spec.ts │ ├── user.service.spec.ts │ ├── theme.service.spec.ts │ ├── auth │ │ ├── oauth.service.spec.ts │ │ ├── account.service.spec.ts │ │ ├── error-interceptor.service.spec.ts │ │ ├── admin-guard.service.spec.ts │ │ ├── loading-interceptor.service.spec.ts │ │ ├── login-guard.service.spec.ts │ │ ├── token-interceptor.service.spec.ts │ │ ├── authentication.service.spec.ts │ │ ├── auth-guard.service.spec.ts │ │ ├── account.service.ts │ │ ├── admin-guard.service.ts │ │ ├── error-interceptor.service.ts │ │ ├── login-guard.service.ts │ │ ├── token-interceptor.service.ts │ │ ├── loading-interceptor.service.ts │ │ └── auth-guard.service.ts │ ├── dashboard │ │ ├── dashboard.component.css │ │ └── dashboard.component.spec.ts │ ├── language.service.spec.ts │ ├── toast-service.ts │ ├── contributors │ │ ├── contributors.component.css │ │ └── contributors.component.spec.ts │ ├── importer │ │ ├── importer │ │ │ ├── importer.component.css │ │ │ ├── importer.component.spec.ts │ │ │ └── importer.component.html │ │ └── importer.module.ts │ ├── profile │ │ ├── profile.component.spec.ts │ │ └── profile.component.css │ ├── not-found │ │ ├── not-found.component.spec.ts │ │ ├── not-found.component.html │ │ └── not-found.component.ts │ ├── home │ │ ├── home.component.spec.ts │ │ └── home.component.css │ ├── supportedBrowsers.ts │ ├── message.service.ts │ ├── app.component.spec.ts │ ├── dialog.component.ts │ ├── toasts-container.component.ts │ ├── dialog.service.ts │ ├── language.service.ts │ └── api.service.ts ├── favicon.ico ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── main.ts ├── index.html ├── test.ts ├── styles │ └── public.ranking.scss └── manifest.webmanifest ├── proxy.conf.json ├── e2e ├── tsconfig.json ├── src │ ├── app.po.ts │ └── app.e2e-spec.ts └── protractor.conf.js ├── .editorconfig ├── tsconfig.spec.json ├── tsconfig.app.json ├── .github └── dependabot.yml ├── .browserslistrc ├── tsconfig.json ├── .gitignore ├── README.md ├── ngsw-config.json ├── ssl ├── naominet.live.crt ├── LocalRootCA.crt └── naominet.live.key └── karma.conf.js /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/admin/admin.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/message/message.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/message/message.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/oauth-callback/oauth-callback.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/announcements/announcements.component.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/announcements/announcement/announcement.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-profile/v2-profile.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-profile/maimai2-profile.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-setting/maimai2-setting.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-songlist/maimai2-songlist.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/cards/cards.component.css: -------------------------------------------------------------------------------- 1 | a{ 2 | cursor: pointer; 3 | } 4 | -------------------------------------------------------------------------------- /src/app/announcements/edit/edit.component.css: -------------------------------------------------------------------------------- 1 | .announcement-content{ 2 | height: 50vh 3 | } 4 | -------------------------------------------------------------------------------- /src/app/password-reset/password-reset.component.css: -------------------------------------------------------------------------------- 1 | .btn-get-verify-code{ 2 | width: 4em; 3 | } 4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-music-ranking/ongeki-music-ranking.component.scss: -------------------------------------------------------------------------------- 1 | @import "src/styles/public.ranking"; 2 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-user-ranking/ongeki-user-ranking.component.scss: -------------------------------------------------------------------------------- 1 | @import "src/styles/public.ranking"; 2 | -------------------------------------------------------------------------------- /proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "/api": { 3 | "target": "http://38.147.172.133:6341", 4 | "secure": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanFrame.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanFrame { 2 | id: number; 3 | name: string; 4 | } -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanMapIcon.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanMapIcon { 2 | id: number; 3 | name: string; 4 | } -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanTrophy.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanTrophy { 2 | id: number; 3 | name: string; 4 | } -------------------------------------------------------------------------------- /src/assets/not_found.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/not_found.webp -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanNamePlate.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanNamePlate { 2 | id: number; 3 | name: string; 4 | } -------------------------------------------------------------------------------- /src/app/model/PropertyEntry.ts: -------------------------------------------------------------------------------- 1 | export interface PropertyEntry { 2 | propertyKey: string; 3 | propertyValue: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanSystemVoice.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanSystemVoice { 2 | id: number; 3 | name: string; 4 | } -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiPcRanking.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiPcRanking{ 2 | username: string; 3 | pc: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-setting/ongeki-setting.component.css: -------------------------------------------------------------------------------- 1 | .version { 2 | font-family: 'Fira Code', sans-serif; 3 | } 4 | -------------------------------------------------------------------------------- /src/assets/icons/turtle-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-72x72.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-96x96.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-128x128.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-144x144.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-152x152.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-192x192.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-384x384.png -------------------------------------------------------------------------------- /src/assets/icons/turtle-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RinNET-OpenSource/RinNET_frontend/HEAD/src/assets/icons/turtle-512x512.png -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiTrophy.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiTrophy { 2 | id: number; 3 | name: string; 4 | rarityType: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/model/Page.ts: -------------------------------------------------------------------------------- 1 | export interface Page { 2 | content: T[]; 3 | page: number; 4 | totalPages: number; 5 | totalElements: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanAvatarAcc.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanAvatarAcc { 2 | id: number; 3 | name: string; 4 | category: number; 5 | } -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2PcRanking.ts: -------------------------------------------------------------------------------- 1 | export interface V2PcRanking{ 2 | username: string; 3 | characterId: string; 4 | pc: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2Item.ts: -------------------------------------------------------------------------------- 1 | export interface V2Item { 2 | itemKind: number; 3 | itemId: number; 4 | stock: number; 5 | name: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2SymbolChat.ts: -------------------------------------------------------------------------------- 1 | export interface V2SymbolChat { 2 | sceneId: number; 3 | orderId: number; 4 | symbolChatId: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiSkill.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiSkill { 2 | id: number; 3 | name: string; 4 | category: string; 5 | info: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiCharacter.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiCharacter { 2 | id: number; 3 | name: string; 4 | cv: string; 5 | modelId: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserCircleData.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2UserCircleData { 2 | id: number; 3 | circleId: number; 4 | lastLoginDate: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2FestaSideData.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2FestaSideData { 2 | festaSideId: number; 3 | rankInPlace: number; 4 | advantagePercent: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | apiServer: '/', 3 | production: true, 4 | enableImages: true, 5 | assetsHost: 'https://rinnet.stehp.cn/' 6 | }; 7 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2UserRanking.ts: -------------------------------------------------------------------------------- 1 | export interface V2UserRanking{ 2 | userName: string; 3 | characterId: number; 4 | nowRating: number; 5 | highestRating: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sign-in/sign-in.component.css: -------------------------------------------------------------------------------- 1 | .form-label{ 2 | margin-inline-start: 0.2em; 3 | } 4 | 5 | .oauth-icon { 6 | height: 1.4em; 7 | width: 1.4em; 8 | margin-inline: 1em; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiUserRanking.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiUserRanking{ 2 | userName: string; 3 | ranking: number; 4 | cardId: string; 5 | nowRating: number; 6 | highestRating: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2DxPass.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2DxPass { 2 | cardId: number; 3 | cardTypeId: number; 4 | charaId: number; 5 | mapId: number; 6 | startDate: Date; 7 | endDate: Date; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2Photo.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2Photo { 2 | divLength: number; 3 | fileName: string; 4 | placeId: number; 5 | uploadDate: Date; 6 | playlogId: number; 7 | trackNo: number; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/util/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "sourceMap": true 6 | }, 7 | "exclude": [ 8 | "node_modules" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanSymbolChat.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanSymbolChat { 2 | id: number; 3 | name: string; 4 | sortName: string; 5 | text: string; 6 | balloonId: number; 7 | sceneIds: number[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanCharacter.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanCharacter { 2 | id: number; 3 | name: string; 4 | releaseTag: string; 5 | worksName: string; 6 | illustratorName: string; 7 | addImages: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiGameRanking.ts: -------------------------------------------------------------------------------- 1 | import {OngekiMusic} from './OngekiMusic'; 2 | 3 | export interface OngekiGameRanking { 4 | music: OngekiMusic; 5 | playCount: number; 6 | ranking: number; 7 | state: number; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/sign-up/sign-up.component.css: -------------------------------------------------------------------------------- 1 | .input-group-btn{ 2 | width: 5em; 3 | } 4 | 5 | .form-label{ 6 | margin-inline-start: 0.2em; 7 | } 8 | 9 | .oauth-icon { 10 | height: 1.4em; 11 | width: 1.4em; 12 | margin-inline: 1em; 13 | } 14 | -------------------------------------------------------------------------------- /src/app/util/ordinal.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { OrdinalPipe } from './ordinal.pipe'; 2 | 3 | describe('OrdinalPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new OrdinalPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2CircleFestaRankInfo.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2CircleFestaData } from "./Maimai2CircleFestaData"; 2 | 3 | export interface Maimai2CircleFestaRankInfo { 4 | circleFestaData: Maimai2CircleFestaData; 5 | rank: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-rank.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {ToRankPipe} from './to-rank.pipe'; 2 | 3 | describe('ToRankPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToRankPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/util/to-date.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ToDatePipe } from './to-date.pipe'; 2 | 3 | describe('ToLocaleDateStringPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToDatePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-rating.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {ToRatingPipe} from './to-rating.pipe'; 2 | 3 | describe('ToRatingPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToRatingPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2RequestJoinCircleUser.ts: -------------------------------------------------------------------------------- 1 | import { DisplayMaimai2Profile } from "./Maimai2Profile"; 2 | 3 | export interface Maimai2RequestJoinCircleUser { 4 | userProfile: DisplayMaimai2Profile; 5 | requestTime: string; 6 | userCode: string; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserCirclePointData.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2UserCirclePointData { 2 | id: number; 3 | circleId: number; 4 | userName: string; 5 | aggrDate: string; 6 | point: number; 7 | recordDate: string; 8 | rewardGet: boolean; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserCirclePointRankingResult.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2UserCirclePointRankingResult { 2 | id: number; 3 | circleId: number; 4 | aggrDate: string; 5 | circleName: string; 6 | lastMonthCircleRank: number; 7 | lastMonthPoint: number; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/model/ApiResponse.ts: -------------------------------------------------------------------------------- 1 | export interface ApiResponse { 2 | data: T; 3 | time: string; 4 | status: { 5 | code: number, 6 | message: string 7 | }; 8 | } 9 | 10 | export function isOk(resp: ApiResponse) { 11 | return resp?.status?.code == 9_200_1; 12 | } -------------------------------------------------------------------------------- /src/app/util/to-date.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toDate' 5 | }) 6 | export class ToDatePipe implements PipeTransform { 7 | 8 | transform(value: string): Date { 9 | return new Date(value); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-tech-rating.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ToTechRatingPipe } from './to-tech-rating.pipe'; 2 | 3 | describe('ToTechRatingPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToTechRatingPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-tech-sprite.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {ToTechSpritePipe} from './to-tech-sprite.pipe'; 2 | 3 | describe('ToTechSpritePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToTechSpritePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es2018", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-tech-rating.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ToTechRatingPipe } from './to-tech-rating.pipe'; 2 | 3 | describe('ToTechRatingPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToTechRatingPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2Rival.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2Rival { 2 | rivalName: string; 3 | rivalId: string; 4 | iconId: number; 5 | playerRating: number; 6 | lastPlayDate: string; 7 | awakenCount: number; 8 | playCount: number; 9 | isFavourite: boolean; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-level-string.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ToLevelStringPipe } from './to-level-string.pipe'; 2 | 3 | describe('ToLevelStringPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToLevelStringPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-battle-sprite.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {ToBattleSpritePipe} from './to-battle-sprite.pipe'; 2 | 3 | describe('ToBattleSpritePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToBattleSpritePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-level-decimal.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {ToLevelDecimalPipe} from './to-level-decimal.pipe'; 2 | 3 | describe('ToLevelDecimalPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToLevelDecimalPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-rarity-sprite.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ToRaritySpritePipe } from './to-rarity-sprite.pipe'; 2 | 3 | describe('ToRaritySpritePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToRaritySpritePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/character-image.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { CharacterImagePipe } from './character-image.pipe'; 2 | 3 | describe('CharacterImagePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new CharacterImagePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-setting/maimai2-upload-user-portrait/maimai2-upload-user-portrait.dialog.css: -------------------------------------------------------------------------------- 1 | /* Ensure the size of the image fit the container perfectly */ 2 | img { 3 | display: block; 4 | 5 | /* This rule is very important, please don't ignore this */ 6 | max-width: 100%; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/cource-id-to-class.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {CourceIdToClassPipe} from './cource-id-to-class.pipe'; 2 | 3 | describe('CourceIdToClassPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new CourceIdToClassPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-attribute-class.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import {ToAttributeClassPipe} from './to-attribute-class.pipe'; 2 | 3 | describe('ToAttributeClassPipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToAttributeClassPipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-rating.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toRating' 5 | }) 6 | export class ToRatingPipe implements PipeTransform { 7 | 8 | transform(value: number): number { 9 | return Math.floor(value) / 100; 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-rival/maimai2-rival.component.css: -------------------------------------------------------------------------------- 1 | .profile-icon{ 2 | height: 5.4em; 3 | width: 5.4em; 4 | } 5 | 6 | .profile-table{ 7 | font-size: .8em; 8 | max-width: 20em; 9 | } 10 | 11 | .profile-table th{ 12 | width: 50%; 13 | } 14 | 15 | .profile-table td{ 16 | width: 50%; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2CircleFestaData.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2Circle } from "./Maimai2Circle"; 2 | 3 | export interface Maimai2CircleFestaData { 4 | circleId: number; 5 | eventId: number; 6 | festaSideId: number; 7 | 8 | placeId: number; 9 | totalPoint: number; 10 | circleName: string; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-tech-honor-sprite.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { ToTechHonorSpritePipe } from './to-tech-honor-sprite.pipe'; 2 | 3 | describe('ToTechHonorSpritePipe', () => { 4 | it('create an instance', () => { 5 | const pipe = new ToTechHonorSpritePipe(); 6 | expect(pipe).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /src/app/util/array-utils.ts: -------------------------------------------------------------------------------- 1 | export class ArrayUtils { 2 | static shuffleArray(array: T[]): T[] { 3 | for (let i = array.length - 1; i > 0; i--) { 4 | const j = Math.floor(Math.random() * (i + 1)); 5 | [array[i], array[j]] = [array[j], array[i]]; 6 | } 7 | return array; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import {browser, by, element} from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2GameResultFestaData.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2FestaSideData } from "./Maimai2FestaSideData"; 2 | 3 | type Maimai2ResultFestaSideData = Maimai2FestaSideData; 4 | 5 | export interface Maimai2GameResultFestaData { 6 | eventId: number; 7 | resultFestaSideDataList: Maimai2ResultFestaSideData[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/app/keychip/keychip.component.css: -------------------------------------------------------------------------------- 1 | .keychip-card-header{ 2 | display: flex; 3 | flex-direction: row; 4 | align-items: center; 5 | flex-wrap: nowrap; 6 | gap: .5rem; 7 | } 8 | 9 | .keychip-card-title{ 10 | overflow: hidden; 11 | text-overflow: ellipsis; 12 | white-space: nowrap; 13 | max-width: 100%; 14 | } 15 | -------------------------------------------------------------------------------- /src/app/message/message.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {MessageComponent} from './message.component'; 4 | 5 | @NgModule({ 6 | imports: [ 7 | ], 8 | exports: [MessageComponent], 9 | declarations: [MessageComponent], 10 | providers: [], 11 | }) 12 | export class MessageModule { 13 | } 14 | -------------------------------------------------------------------------------- /src/app/util/formatnumber.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import {FormatnumberPipe} from './formatnumber.pipe'; 4 | 5 | describe('Pipe: Formatnumbere', () => { 6 | it('create an instance', () => { 7 | let pipe = new FormatnumberPipe(); 8 | expect(pipe).toBeTruthy(); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiRival.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiRival { 2 | rivalUserId: number; 3 | rivalUserName: string; 4 | rivalNowRating: number; 5 | rivalHighestRating: number; 6 | rivalCardId: number; 7 | lastPlayDate: string; 8 | reincarnationNum: number; 9 | rivalBattleScore: number; 10 | level: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2Circle.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2Circle { 2 | circleId: number; 3 | circleClass: number; 4 | circleName: String; 5 | isPlace: boolean; 6 | placeId: number; 7 | isPublic: boolean; 8 | aggrDate: string; 9 | circleCode: string; 10 | comment: string; 11 | isAllowAnyoneJoin: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2GameFestaData.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2FestaSideData } from "./Maimai2FestaSideData"; 2 | 3 | export interface Maimai2GameFestaData { 4 | eventId: number; 5 | isRallyPeriod: boolean; 6 | isCircleJoinNotAllowed: boolean; 7 | jackingFestaSideId: number; 8 | festaSideDataList: Maimai2FestaSideData[]; 9 | } 10 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiMusic.ts: -------------------------------------------------------------------------------- 1 | export interface OngekiMusic { 2 | id: number; 3 | name: string; 4 | sortName: string; 5 | artistName: string; 6 | genre: string; 7 | bossCardId: number; 8 | bossLevel: number; 9 | level0: string; 10 | level1: string; 11 | level2: string; 12 | level3: string; 13 | level4: string; 14 | } 15 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card/ongeki-card.component.css: -------------------------------------------------------------------------------- 1 | .deck-row{ 2 | max-width: 720px; 3 | } 4 | 5 | .cards-col { 6 | transition: all .2s cubic-bezier(0.00, 0.00, 0.00, 1.00); 7 | width: 100%; 8 | --pseudo-opacity: 0; 9 | --pseudo-left: 50%; 10 | --pseudo-top: 50%; 11 | } 12 | 13 | .cards-col:hover { 14 | transform: scale(104%); 15 | } 16 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-rival-list/ongeki-rival-list.component.css: -------------------------------------------------------------------------------- 1 | table { 2 | width: 100%; 3 | } 4 | 5 | .profile-icon{ 6 | height: 5.4em; 7 | width: 5.4em; 8 | } 9 | 10 | .profile-table{ 11 | font-size: .8em; 12 | max-width: 20em; 13 | } 14 | 15 | .profile-table th{ 16 | width: 50%; 17 | } 18 | 19 | .profile-table td{ 20 | width: 50%; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-name-setting/v2-name-setting.scss: -------------------------------------------------------------------------------- 1 | .btns { 2 | display: flex; 3 | justify-content: space-between; 4 | gap: 0.4rem; 5 | flex-wrap: wrap; 6 | 7 | button { 8 | width: 2rem !important; 9 | height: 2rem !important; 10 | } 11 | 12 | &:after { 13 | content: ""; 14 | flex: auto; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/app/util/full-width.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { TestBed, async } from '@angular/core/testing'; 4 | import { FullWidthPipe } from './full-width.pipe'; 5 | 6 | describe('Pipe: FullWidthe', () => { 7 | it('create an instance', () => { 8 | let pipe = new FullWidthPipe(); 9 | expect(pipe).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/PlayerRatingItem.ts: -------------------------------------------------------------------------------- 1 | import {OngekiMusic} from './OngekiMusic'; 2 | import {OngekiCard} from './OngekiCard'; 3 | 4 | export interface PlayerRatingItem { 5 | musicId: number; 6 | level: number; 7 | value: number; 8 | platinumScoreMax: number; 9 | platinumScoreStar: number; 10 | musicInfo?: OngekiMusic; 11 | bossCardInfo?: OngekiCard; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/announcements/announcement/announcement.component.html: -------------------------------------------------------------------------------- 1 | 5 | 8 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node", 8 | "@angular/localize" 9 | ] 10 | }, 11 | "files": [ 12 | "src/test.ts", 13 | "src/polyfills.ts" 14 | ], 15 | "include": [ 16 | "src/**/*.spec.ts", 17 | "src/**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [ 6 | "@angular/localize" 7 | ] 8 | }, 9 | "files": [ 10 | "src/main.ts", 11 | "src/polyfills.ts" 12 | ], 13 | "include": [ 14 | "src/**/*.d.ts" 15 | ], 16 | "exclude": [ 17 | "src/test.ts", 18 | "src/**/*.spec.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/assets/microsoft.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/app/util/to-date.pipe.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"to-date.pipe.js","sourceRoot":"","sources":["to-date.pipe.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAYA;;;AAZA,sCAAoD;AAKpD;4BAHC,IAAA,WAAI,EAAC;YACJ,IAAI,EAAE,QAAQ;SACf,CAAC;;;;QACW,UAAU;;QAMvB,CAAC;QAJC,gCAAS,GAAT,UAAU,KAAa;YACrB,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QAEH,mBAAC;IAAD,CAAC;;;QAND,wJAMC;QANY,UAAU;QAAV,uDAAU;;WAAV,UAAU;IAMtB"} -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import {enableProdMode} from '@angular/core'; 2 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 3 | 4 | import {AppModule} from './app/app.module'; 5 | import {environment} from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/app/database/preload.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { PreloadService } from './preload.service'; 4 | 5 | describe('PreloadService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: PreloadService = TestBed.get(PreloadService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2Character.ts: -------------------------------------------------------------------------------- 1 | import {ChusanCharacter} from './ChusanCharacter'; 2 | 3 | export interface V2Character { 4 | characterId: number; 5 | playCount: number; 6 | level: number; 7 | friendshipExp: number; 8 | isValid: boolean; 9 | isNewMark: boolean; 10 | exMaxLv: number; 11 | assignIllust: number; 12 | param1: string; 13 | param2: string; 14 | characterInfo: ChusanCharacter; 15 | } 16 | -------------------------------------------------------------------------------- /src/app/menu.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { MenuService } from './menu.service'; 4 | 5 | describe('MenuService', () => { 6 | let service: MenuService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(MenuService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { UserService } from './user.service'; 4 | 5 | describe('UserService', () => { 6 | let service: UserService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(UserService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-level-string.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import {ChusanMusicLevelInfo} from '../model/ChusanMusic'; 3 | 4 | @Pipe({ 5 | name: 'toLevelString' 6 | }) 7 | export class ToLevelStringPipe implements PipeTransform { 8 | 9 | transform(level: ChusanMusicLevelInfo): string { 10 | return `${level.level}.${level.levelDecimal.toString().charAt(0)}` ?? '0'; 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/app/theme.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ThemeService } from './theme.service'; 4 | 5 | describe('ThemeService', () => { 6 | let service: ThemeService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(ThemeService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/auth/oauth.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { OauthService } from './oauth.service'; 4 | 5 | describe('OauthService', () => { 6 | let service: OauthService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(OauthService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/message/message.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Injectable, OnInit} from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | @Component({ 7 | selector: 'app-message', 8 | templateUrl: './message.component.html', 9 | styleUrls: ['./message.component.css'] 10 | }) 11 | export class MessageComponent implements OnInit { 12 | 13 | 14 | constructor( 15 | ) { 16 | } 17 | 18 | 19 | ngOnInit() {} 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/app/auth/account.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AccountService } from './account.service'; 4 | 5 | describe('AccountService', () => { 6 | let service: AccountService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(AccountService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/dashboard/dashboard.component.css: -------------------------------------------------------------------------------- 1 | .profile-icon{ 2 | height: 5.4em; 3 | width: 5.4em; 4 | } 5 | 6 | .profile-table{ 7 | font-size: .8em; 8 | max-width: 20em; 9 | } 10 | 11 | .profile-table th{ 12 | width: 50%; 13 | } 14 | 15 | .profile-table td{ 16 | width: 50%; 17 | } 18 | 19 | .more-announcements{ 20 | text-decoration: none; 21 | font-size: small; 22 | } 23 | 24 | .more-announcements:hover{ 25 | text-decoration: underline; 26 | } 27 | -------------------------------------------------------------------------------- /src/app/language.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LanguageService } from './language.service'; 4 | 5 | describe('LanguageService', () => { 6 | let service: LanguageService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LanguageService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/util/formatnumber.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'formatNumber' 5 | }) 6 | export class FormatnumberPipe implements PipeTransform { 7 | 8 | public transform(value: number, length?: number): string { 9 | if (value === null) { return null; } 10 | let str = value.toString(); 11 | while (str.length < length) { 12 | str = '0' + str; 13 | } 14 | return str; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/auth/error-interceptor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | 3 | import {ErrorInterceptorService} from './error-interceptor.service'; 4 | 5 | describe('ErrorInterceptorService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ErrorInterceptorService = TestBed.get(ErrorInterceptorService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-level/ongeki-card-level.component.css: -------------------------------------------------------------------------------- 1 | .level-container{ 2 | bottom: 0; 3 | --bs-aspect-ratio: 40.2985074626866%; 4 | background-size: 100% 100%; 5 | background-position: left bottom; 6 | background-repeat: no-repeat; 7 | } 8 | .level-container .level-number{ 9 | height:60%; 10 | margin-top: 3%; 11 | } 12 | .level-container .level-header{ 13 | height: 50%; 14 | padding: 0; 15 | margin-top: 8%; 16 | margin-left: -5%; 17 | } 18 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2CircleMemberInfo.ts: -------------------------------------------------------------------------------- 1 | import { DisplayMaimai2Profile } from "./Maimai2Profile"; 2 | import { Maimai2UserCircleData } from "./Maimai2UserCircleData"; 3 | import { Maimai2UserCirclePointData } from "./Maimai2UserCirclePointData"; 4 | 5 | export interface Maimai2CircleMemberInfo { 6 | userCode: string; 7 | userProfile: DisplayMaimai2Profile; 8 | userCircleData: Maimai2UserCircleData; 9 | userCirclePointData: Maimai2UserCirclePointData; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2GameFestaInfo.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2GameFesta } from "./Maimai2GameFesta"; 2 | import { Maimai2GameFestaData } from "./Maimai2GameFestaData"; 3 | import { Maimai2GameResultFestaData } from "./Maimai2GameResultFestaData"; 4 | 5 | export interface Maimai2GameFestaInfo { 6 | gameFesta: Maimai2GameFesta; 7 | gameFestaData: Maimai2GameFestaData; 8 | gameRsultFesta: Maimai2GameFesta; 9 | gameResultFestaData: Maimai2GameResultFestaData; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/new-rating.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { NewRatingService } from './new-rating.service'; 4 | 5 | describe('RatingService', () => { 6 | let service: NewRatingService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(NewRatingService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/auth/admin-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { AdminGuardService } from './admin-guard.service'; 4 | 5 | describe('AdminGuardService', () => { 6 | let service: AdminGuardService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(AdminGuardService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/auth/loading-interceptor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import {TestBed} from '@angular/core/testing'; 2 | 3 | import {LoadingInterceptorService} from './loading-interceptor.service'; 4 | 5 | describe('LoadingInterceptorService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: LoadingInterceptorService = TestBed.get(LoadingInterceptorService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/app/auth/login-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginGuardService } from './login-guard.service'; 4 | 5 | describe('LoginGuardService', () => { 6 | let service: LoginGuardService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(LoginGuardService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/character-image.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'characterImage' 5 | }) 6 | export class CharacterImagePipe implements PipeTransform { 7 | 8 | transform(characterId: number): string { 9 | const prefix = Math.floor(characterId / 10).toString().padStart(4, '0'); 10 | const suffix = (characterId % 10).toString().padStart(2, '0'); 11 | return `${prefix}_${suffix}`; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-rarity-sprite.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toRaritySprite' 5 | }) 6 | export class ToRaritySpritePipe implements PipeTransform { 7 | 8 | transform(value: string): string { 9 | switch (value){ 10 | case 'N': return'N'; 11 | case 'R': return'R'; 12 | case 'SR': return'SR'; 13 | case 'SRPlus': return'SR_plus'; 14 | case 'SSR': return'SSR'; 15 | } 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2Record.ts: -------------------------------------------------------------------------------- 1 | export interface V2Record { 2 | musicId: number; 3 | level: number; 4 | playCount: number; 5 | scoreMax: number; 6 | resRequestCount: number; 7 | resAcceptCount: number; 8 | resSuccessCount: number; 9 | missCount: number; 10 | maxComboCount: number; 11 | isFullCombo: boolean; 12 | isAllJustice: boolean; 13 | isSuccess: boolean; 14 | fullChain: number; 15 | maxChain: number; 16 | scoreRank: number; 17 | isLock: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/release-tag.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ReleaseTagService } from './release-tag.service'; 4 | 5 | describe('ReleaseTagService', () => { 6 | let service: ReleaseTagService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(ReleaseTagService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-rival-list/v2-rival-list.component.css: -------------------------------------------------------------------------------- 1 | table { 2 | width: 100%; 3 | } 4 | 5 | .profile-icon{ 6 | height: 5.4em; 7 | width: 5.4em; 8 | } 9 | 10 | .profile-table{ 11 | font-size: .8em; 12 | max-width: 20em; 13 | } 14 | 15 | .profile-table th{ 16 | width: 50%; 17 | } 18 | 19 | .profile-table td{ 20 | width: 50%; 21 | } 22 | 23 | .friend-header { 24 | display: flex; 25 | justify-content: space-between; 26 | align-items: center; 27 | } 28 | -------------------------------------------------------------------------------- /src/app/toast-service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, TemplateRef } from '@angular/core'; 2 | 3 | @Injectable({ providedIn: 'root' }) 4 | export class ToastService { 5 | toasts: any[] = []; 6 | 7 | show(textOrTpl: string | TemplateRef, options: any = {}) { 8 | this.toasts.push({ textOrTpl, ...options }); 9 | } 10 | 11 | remove(toast) { 12 | this.toasts = this.toasts.filter((t) => t !== toast); 13 | } 14 | 15 | clear() { 16 | this.toasts.splice(0, this.toasts.length); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/app/auth/token-interceptor.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { TokenInterceptorService } from './token-interceptor.service'; 4 | 5 | describe('TokenInterceptorService', () => { 6 | let service: TokenInterceptorService; 7 | 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({}); 10 | service = TestBed.inject(TokenInterceptorService); 11 | }); 12 | 13 | it('should be created', () => { 14 | expect(service).toBeTruthy(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/app/util/tools.module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"tools.module.js","sourceRoot":"","sources":["tools.module.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAwBA;;;AAxBA,sCAAuC;AACvC,0CAA6C;AAC7C,yDAAqD;AACrD,qDAAgD;AAChD,+CAA0C;AAkB1C;4BAfC,IAAA,eAAQ,EAAC;YACR,YAAY,EAAE;gBACZ,oCAAgB;gBAChB,+BAAa;gBACb,yBAAU;aACV;YACF,OAAO,EAAE;gBACP,qBAAY;aACb;YACC,OAAO,EAAE;gBACP,oCAAgB;gBAChB,+BAAa;gBACb,yBAAU;aACX;SACJ,CAAC;;;;QACW,WAAW;;QACxB,CAAC;QAAD,oBAAC;IAAD,CAAC;;;QADD,wJACC;QADY,WAAW;QAAX,uDAAW;;WAAX,WAAW;IACvB"} -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserFestaInfo.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2Circle } from "./Maimai2Circle"; 2 | import { Maimai2CircleFestaData } from "./Maimai2CircleFestaData"; 3 | import { Maimai2UserFestaData } from "./Maimai2UserFestaData"; 4 | import { Maimai2UserResultFestaData } from "./Maimai2UserResultFestaData"; 5 | 6 | export interface Maimai2UserFestaInfo { 7 | circle: Maimai2Circle; 8 | circleFestaData: Maimai2CircleFestaData; 9 | userFestaData: Maimai2UserFestaData; 10 | userResultFestaData: Maimai2UserResultFestaData; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/PlayerNewRatingItem.ts: -------------------------------------------------------------------------------- 1 | import {OngekiMusic} from './OngekiMusic'; 2 | 3 | export interface PlayerNewRatingItem { 4 | musicId: number; 5 | level: number; 6 | techScoreMax: number; 7 | platinumScoreMax: number; 8 | platinumScoreStar: number; 9 | isFullBell?: boolean; 10 | isFullCombo?: boolean; 11 | isAllBreak?: boolean; 12 | clearMarkType?: ClearMarkType; 13 | musicInfo?: OngekiMusic; 14 | } 15 | 16 | export enum ClearMarkType { 17 | None, 18 | FullCombo, 19 | AllBreak, 20 | AllBreakPlus 21 | } 22 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-level-decimal.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toLevelDecimal' 5 | }) 6 | export class ToLevelDecimalPipe implements PipeTransform { 7 | 8 | transform(value: string): string { 9 | if (value === null) { return null; } 10 | value = value.replace(',', '.'); 11 | if (value.charAt(value.length - 1) === '0' && value.charAt(value.length - 2) !== '.') { 12 | value = value.slice(0, value.length - 1); 13 | } 14 | return value; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/app/util/debounce.ts: -------------------------------------------------------------------------------- 1 | export function debounce( 2 | func: (...args: any) => any, 3 | delay: number, 4 | ) { 5 | let timer: ReturnType; 6 | 7 | // tslint:disable-next-line:variable-name 8 | const _debounce = function(...args: any[]) { 9 | if (timer) { clearTimeout(timer); } 10 | 11 | timer = setTimeout(() => { 12 | func.apply(this, args); 13 | }, delay); 14 | }; 15 | 16 | _debounce.cancel = () => { 17 | if (timer) { clearTimeout(timer); } 18 | }; 19 | 20 | return _debounce; 21 | } 22 | -------------------------------------------------------------------------------- /src/app/util/array-utils.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"array-utils.js","sourceRoot":"","sources":["array-utils.ts"],"names":[],"mappings":";;;AAAA;IAAA;IAQA,CAAC;IAPQ,uBAAY,GAAnB,UAAuB,KAAU;;QAC/B,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YACzC,IAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC9C,KAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAA1C,KAAK,CAAC,CAAC,CAAC,QAAA,EAAE,KAAK,CAAC,CAAC,CAAC,QAAA,CAAyB;SAC7C;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACH,iBAAC;AAAD,CAAC,AARD,IAQC;AARY,gCAAU"} -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "npm" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanRival.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanRival { 2 | rivalName: string; 3 | rivalId: string; 4 | playerRating: number; 5 | characterId: number; 6 | overPowerRate: number; 7 | isFavorite: boolean; 8 | reincarnationNum: number; 9 | level: number; 10 | } 11 | 12 | export interface ChusanProfile { 13 | userName: string; 14 | level: number; 15 | reincarnationNum: number; 16 | playerRating: number; 17 | overPowerRate: number; 18 | characterId: number; 19 | lastPlayDate: string; 20 | rivalId: string; 21 | } 22 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | unreleased versions 11 | Firefox ESR 12 | fully supports es6-module and fully supports css-grid and last 3 years 13 | not dead 14 | not IE 6-11 15 | not kaios 2.5 16 | not op_mini all 17 | -------------------------------------------------------------------------------- /src/app/contributors/contributors.component.css: -------------------------------------------------------------------------------- 1 | .sponsor-me{ 2 | background: linear-gradient(90deg,#946ce6,#7e5fd9); 3 | border-radius: .1em; 4 | color: #fff; 5 | padding: .5rem 2rem; 6 | font-weight: bold; 7 | font-size: small; 8 | } 9 | 10 | .sponsor-me:hover { 11 | background: linear-gradient(90deg,#946ce6,#885fd9); 12 | } 13 | 14 | .webstorm-logo{ 15 | height: 4rem; 16 | border-radius: .3rem; 17 | padding: .5rem; 18 | } 19 | 20 | .jetbrains-logo{ 21 | height: 4em 22 | } 23 | 24 | .avator{ 25 | height: 2em; 26 | aspect-ratio: 1; 27 | border-radius: 50% 28 | } 29 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserResultFestaData.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2Circle } from "./Maimai2Circle"; 2 | import { Maimai2CircleFestaData } from "./Maimai2CircleFestaData"; 3 | 4 | export interface Maimai2UserResultFestaData { 5 | 6 | /** 7 | * 请注意这个eventId对应的是Festa.xml的resultEventId 8 | */ 9 | eventId: number; 10 | 11 | circleId: number; 12 | 13 | circleName: string; 14 | 15 | festaSideId: number; 16 | 17 | circleRankInFestaSide: number; 18 | 19 | receivedRewardBorder: number; 20 | 21 | circleTotalFestaPoint: number; 22 | 23 | resultRewardGet: number; 24 | } 25 | -------------------------------------------------------------------------------- /src/app/util/full-width.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'fullWidth' 5 | }) 6 | export class FullWidthPipe implements PipeTransform { 7 | 8 | transform(value: string): string { 9 | return Array.from(value).map((char) => { 10 | const code = char.charCodeAt(0); 11 | if (code === 0x20) { 12 | return String.fromCharCode(0x3000); 13 | } else if (code >= 0x21 && code <= 0x7e) { 14 | return String.fromCharCode(code + 0xfee0); 15 | } 16 | return char; 17 | }).join(''); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiCard.ts: -------------------------------------------------------------------------------- 1 | import {OngekiSkill} from './OngekiSkill'; 2 | import {OngekiCharacter} from './OngekiCharacter'; 3 | 4 | export interface OngekiCard { 5 | id: number; 6 | name: string; 7 | nickName: string; 8 | attribute: string; 9 | charaId: number; 10 | characterInfo?: OngekiCharacter; 11 | school: string; 12 | gakunen: string; 13 | rarity: string; 14 | levelParam: string; 15 | skillId: number; 16 | skillInfo?: OngekiSkill; 17 | choKaikaSkillId: number; 18 | choKaikaSkillInfo?: OngekiSkill; 19 | cardNumber: string; 20 | version: string; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/chunithm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/app/util/formatnumber.pipe.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"formatnumber.pipe.js","sourceRoot":"","sources":["formatnumber.pipe.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAiBA;;;AAjBA,sCAAkD;AAKlD;4BAHC,IAAA,WAAI,EAAC;YACJ,IAAI,EAAE,cAAc;SACrB,CAAC;;;;QACW,gBAAgB;;QAW7B,CAAC;QATQ,sCAAS,GAAhB,UAAiB,KAAa,EAAE,MAAe;YAC7C,IAAI,KAAK,KAAK,IAAI,EAAE;gBAAE,OAAO,IAAI,CAAC;aAAE;YACpC,IAAI,GAAG,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3B,OAAO,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE;gBAC1B,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;aACjB;YACD,OAAO,GAAG,CAAC;QACb,CAAC;QAEH,yBAAC;IAAD,CAAC;;;QAXD,wJAWC;QAXY,gBAAgB;QAAhB,uDAAgB;;WAAhB,gBAAgB;IAW5B"} -------------------------------------------------------------------------------- /src/app/importer/importer/importer.component.css: -------------------------------------------------------------------------------- 1 | .upload-button::-webkit-file-upload-button { 2 | visibility: hidden; 3 | } 4 | 5 | .upload-button::before { 6 | content: 'Select File'; 7 | cursor: pointer; 8 | outline: none; 9 | border: none; 10 | -webkit-tap-highlight-color: transparent; 11 | display: inline-block; 12 | white-space: nowrap; 13 | text-decoration: none; 14 | vertical-align: baseline; 15 | text-align: center; 16 | margin: 0; 17 | min-width: 64px; 18 | line-height: 36px; 19 | padding: 0 16px; 20 | border-radius: 4px; 21 | overflow: visible; 22 | background-color: #595959; 23 | } 24 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserCircleInfo.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2Circle } from "./Maimai2Circle"; 2 | import { Maimai2UserCircleData } from "./Maimai2UserCircleData"; 3 | import { Maimai2UserCirclePointData } from "./Maimai2UserCirclePointData"; 4 | import { Maimai2UserCirclePointRankingResult } from "./Maimai2UserCirclePointRankingResult"; 5 | 6 | export interface Maimai2UserCircleInfo { 7 | joinedCircle: Maimai2Circle; 8 | userCircleData: Maimai2UserCircleData; 9 | userCirclePointData: Maimai2UserCirclePointData, 10 | userCirclePointRankingResult: Maimai2UserCirclePointRankingResult; 11 | isCircleOwner: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /src/app/oauth-callback/oauth-callback.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 | OAuth2 Login via {{type.toUpperCase()}} 7 |
8 |
9 |
10 |
11 | Processing 12 |
13 |
14 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-setting.component.css: -------------------------------------------------------------------------------- 1 | .version-box { 2 | display: flex; 3 | justify-content: space-between; 4 | } 5 | 6 | .version-box .card { 7 | width: 49.5%; 8 | } 9 | 10 | .version-box button { 11 | margin-left: 0.3rem; 12 | } 13 | 14 | .version { 15 | font-weight: 500; 16 | font-size: 1.2rem; 17 | } 18 | 19 | @media only screen and (max-width: 575px) { 20 | .version-box { 21 | flex-direction: column; 22 | } 23 | 24 | .version-box .card { 25 | width: 100%; 26 | } 27 | 28 | .version-box .card:nth-child(2) { 29 | margin-top: 1rem; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-userbox/v2-userbox-setting/v2-userbox.setting.css: -------------------------------------------------------------------------------- 1 | .selected { 2 | border: 1px solid var(--bs-primary) !important; 3 | } 4 | 5 | .row > .item-card { 6 | box-sizing: border-box; 7 | padding: 1%; 8 | border-radius: 10px; 9 | border: 1px solid transparent; 10 | cursor: default; 11 | } 12 | 13 | .item-card img{ 14 | object-fit: contain; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | 19 | .item-body{ 20 | display: flex; 21 | align-items: center; 22 | width: 100%; 23 | max-height: 5em; 24 | aspect-ratio: 1.8; 25 | } 26 | 27 | .item-name{ 28 | height: 1em; 29 | } 30 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-setting/maimai2-upload-user-portrait/maimai2-upload-user-portrait.dialog.html: -------------------------------------------------------------------------------- 1 | 5 | 16 | -------------------------------------------------------------------------------- /src/app/auth/authentication.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import {inject, TestBed} from '@angular/core/testing'; 4 | import {AuthenticationService} from './authentication.service'; 5 | import {HttpClientModule} from '@angular/common/http'; 6 | 7 | describe('Service: Authentication', () => { 8 | beforeEach(() => { 9 | TestBed.configureTestingModule({ 10 | imports: [HttpClientModule], 11 | providers: [AuthenticationService] 12 | }); 13 | }); 14 | 15 | it('should ...', inject([AuthenticationService], (service: AuthenticationService) => { 16 | expect(service).toBeTruthy(); 17 | })); 18 | }); 19 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-user-ranking/v2-user-ranking.component.scss: -------------------------------------------------------------------------------- 1 | @import "src/styles/public.ranking"; 2 | 3 | 4 | .nav-link { 5 | transition: all 0.3s ease; 6 | } 7 | 8 | .nav-pills { 9 | border-radius: 10px; 10 | background-color: var(--bs-secondary-bg); 11 | width: fit-content; 12 | 13 | .nav-item { 14 | border-radius: 10px; 15 | .active { 16 | border-radius: 10px; 17 | margin: 0.3rem; 18 | background-color: var(--bs-tertiary-bg); 19 | color: var(--bs-dark-rgb); 20 | } 21 | a { 22 | border-radius: 10px; 23 | margin: 0.3rem; 24 | color: var(--bs-dark-rgb); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-photos/maimai2-photos.component.scss: -------------------------------------------------------------------------------- 1 | .tag { 2 | width: 130px; 3 | } 4 | 5 | .record { 6 | display: flex; 7 | .left { 8 | flex: 1.8; 9 | } 10 | .center { 11 | flex: 1; 12 | } 13 | .right { 14 | flex: 1; 15 | } 16 | } 17 | 18 | .tiny-text { 19 | font-size: 0.7rem; 20 | } 21 | 22 | .flex-container { 23 | display: flex; 24 | flex-wrap: wrap; /* 确保子元素能够换行 */ 25 | } 26 | .left-column { 27 | flex: 1 1 auto; /* flex-grow, flex-shrink, flex-basis */ 28 | min-width: 0; /* 确保左侧列可缩小 */ 29 | } 30 | .right-column { 31 | flex: 0 0; /* 不缩小,宽度自适应 */ 32 | } 33 | 34 | 35 | .no-wrap{ 36 | flex-wrap: nowrap; 37 | } 38 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/PlayerCard.ts: -------------------------------------------------------------------------------- 1 | import {OngekiCard} from './OngekiCard'; 2 | import {OngekiCharacter} from './OngekiCharacter'; 3 | import {OngekiSkill} from './OngekiSkill'; 4 | 5 | export interface PlayerCard { 6 | cardId: number; 7 | digitalStock: number; 8 | analogStock: number; 9 | level: number; 10 | maxLevel: number; 11 | exp: number; 12 | printCount: number; 13 | useCount: number; 14 | kaikaDate: string; 15 | choKaikaDate: string; 16 | skillId: number; 17 | created: string; 18 | isNew: boolean; 19 | isAcquired: boolean; 20 | cardInfo?: OngekiCard; 21 | characterInfo?: OngekiCharacter; 22 | skillInfo?: OngekiSkill; 23 | } 24 | -------------------------------------------------------------------------------- /src/app/util/array-utils.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.ArrayUtils = void 0; 4 | var ArrayUtils = /** @class */ (function () { 5 | function ArrayUtils() { 6 | } 7 | ArrayUtils.shuffleArray = function (array) { 8 | var _a; 9 | for (var i = array.length - 1; i > 0; i--) { 10 | var j = Math.floor(Math.random() * (i + 1)); 11 | _a = [array[j], array[i]], array[i] = _a[0], array[j] = _a[1]; 12 | } 13 | return array; 14 | }; 15 | return ArrayUtils; 16 | }()); 17 | exports.ArrayUtils = ArrayUtils; 18 | //# sourceMappingURL=array-utils.js.map -------------------------------------------------------------------------------- /src/app/admin/admin.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AdminComponent } from './admin.component'; 4 | 5 | describe('AdminComponent', () => { 6 | let component: AdminComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [AdminComponent] 12 | }); 13 | fixture = TestBed.createComponent(AdminComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/cards/cards.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CardsComponent } from './cards.component'; 4 | 5 | describe('CardsComponent', () => { 6 | let component: CardsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [CardsComponent] 12 | }); 13 | fixture = TestBed.createComponent(CardsComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-version-setting/v2-version-setting.dialog.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, Input} from '@angular/core'; 2 | import {V2SettingComponent} from '../v2-setting.component'; 3 | import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; 4 | 5 | @Component({ 6 | selector: 'v2-version-setting-dialog', 7 | templateUrl: 'v2-version-setting.html', 8 | }) 9 | export class V2VersionSettingDialog { 10 | 11 | parentComponent: any; 12 | @Input() public data: V2SettingComponent; 13 | constructor( 14 | public modalService: NgbModal, 15 | ) { 16 | } 17 | 18 | } 19 | 20 | export interface V2VersionSettingDialog { 21 | version: string; 22 | } 23 | -------------------------------------------------------------------------------- /src/app/announcements/edit/edit.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { EditComponent } from './edit.component'; 4 | 5 | describe('EditComponent', () => { 6 | let component: EditComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [EditComponent] 12 | }); 13 | fixture = TestBed.createComponent(EditComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sign-in/sign-in.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SignInComponent } from './sign-in.component'; 4 | 5 | describe('SignInComponent', () => { 6 | let component: SignInComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [SignInComponent] 12 | }); 13 | fixture = TestBed.createComponent(SignInComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sign-up/sign-up.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SignUpComponent } from './sign-up.component'; 4 | 5 | describe('SignUpComponent', () => { 6 | let component: SignUpComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [SignUpComponent] 12 | }); 13 | fixture = TestBed.createComponent(SignUpComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/keychip/keychip.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { KeychipComponent } from './keychip.component'; 4 | 5 | describe('KeychipComponent', () => { 6 | let component: KeychipComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [KeychipComponent] 12 | }); 13 | fixture = TestBed.createComponent(KeychipComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/profile/profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ProfileComponent } from './profile.component'; 4 | 5 | describe('ProfileComponent', () => { 6 | let component: ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ProfileComponent] 12 | }); 13 | fixture = TestBed.createComponent(ProfileComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/util/tools.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {FormatnumberPipe} from './formatnumber.pipe'; 4 | import {FullWidthPipe} from './full-width.pipe'; 5 | import {ToDatePipe} from './to-date.pipe'; 6 | import { OrdinalPipe } from './ordinal.pipe'; 7 | 8 | 9 | @NgModule({ 10 | declarations: [ 11 | FormatnumberPipe, 12 | FullWidthPipe, 13 | ToDatePipe, 14 | OrdinalPipe 15 | ], 16 | imports: [ 17 | CommonModule 18 | ], 19 | exports: [ 20 | FormatnumberPipe, 21 | FullWidthPipe, 22 | ToDatePipe, 23 | OrdinalPipe 24 | ] 25 | }) 26 | export class ToolsModule { 27 | } 28 | -------------------------------------------------------------------------------- /src/app/not-found/not-found.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NotFoundComponent } from './not-found.component'; 4 | 5 | describe('NotFoundComponent', () => { 6 | let component: NotFoundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [NotFoundComponent] 12 | }); 13 | fixture = TestBed.createComponent(NotFoundComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/cource-id-to-class.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'courceIdToClass' 5 | }) 6 | export class CourceIdToClassPipe implements PipeTransform { 7 | 8 | transform(v: number): number { 9 | switch (true) { 10 | case (v === 10): 11 | return 1; 12 | case (v === 11): 13 | return 2; 14 | case (v === 12): 15 | return 3; 16 | case (v === 13): 17 | return 4; 18 | case (v === 14): 19 | return 5; 20 | case (v === 20): 21 | return 6; // infinity 22 | case (v === 21): 23 | return 7; // class unknown 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | 5 | describe('HomeComponent', () => { 6 | let component: HomeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HomeComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(HomeComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "allowSyntheticDefaultImports": true, 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "downlevelIteration": true, 10 | "experimentalDecorators": true, 11 | "module": "es2022", 12 | "moduleResolution": "node", 13 | "importHelpers": true, 14 | "target": "es2022", 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ], 18 | "lib": [ 19 | "es2022", 20 | "dom", 21 | ] 22 | }, 23 | "angularCompilerOptions": { 24 | "fullTemplateTypeCheck": true, 25 | "strictInjectionParameters": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card/ongeki-card.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiCardComponent } from './ongeki-card.component'; 4 | 5 | describe('OngekiCardComponent', () => { 6 | let component: OngekiCardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiCardComponent] 12 | }); 13 | fixture = TestBed.createComponent(OngekiCardComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2UserFestaData.ts: -------------------------------------------------------------------------------- 1 | import { Maimai2Circle } from "./Maimai2Circle"; 2 | import { Maimai2CircleFestaData } from "./Maimai2CircleFestaData"; 3 | 4 | export interface Maimai2UserFestaData { 5 | 6 | /** 7 | * 请注意这个eventId对应的是Festa.xml的openEventId 8 | */ 9 | eventId: number; 10 | 11 | circleId: number; 12 | 13 | festaSideId: number; 14 | 15 | circleTotalFestaPoint: number; 16 | 17 | currentTotalFestaPoint: number; 18 | 19 | circleRankInFestaSide: number; 20 | 21 | circleRecordDate: string; 22 | 23 | isDailyBonus: boolean; 24 | 25 | participationRewardGet: boolean; 26 | 27 | receivedRewardBorder: number; 28 | 29 | circleName: string; 30 | 31 | placeId: number; 32 | } 33 | -------------------------------------------------------------------------------- /src/app/announcements/announcements.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AnnouncementsComponent } from './announcements.component'; 4 | 5 | describe('AnnouncementsComponent', () => { 6 | let component: AnnouncementsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [AnnouncementsComponent] 12 | }); 13 | fixture = TestBed.createComponent(AnnouncementsComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/announcements/announcement/announcement.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AnnouncementComponent } from './announcement.component'; 4 | 5 | describe('AnnouncementComponent', () => { 6 | let component: AnnouncementComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [AnnouncementComponent] 12 | }); 13 | fixture = TestBed.createComponent(AnnouncementComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/auth/auth-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import {inject, TestBed} from '@angular/core/testing'; 4 | import {AuthGuardService} from './auth-guard.service'; 5 | import {HttpClientModule} from '@angular/common/http'; 6 | import {RouterTestingModule} from '@angular/router/testing'; 7 | 8 | describe('Service: AuthGuard', () => { 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | imports: [ 12 | HttpClientModule, 13 | RouterTestingModule 14 | ], 15 | providers: [AuthGuardService] 16 | }); 17 | }); 18 | 19 | it('should ...', inject([AuthGuardService], (service: AuthGuardService) => { 20 | expect(service).toBeTruthy(); 21 | })); 22 | }); 23 | -------------------------------------------------------------------------------- /src/app/oauth-callback/oauth-callback.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OauthCallbackComponent } from './oauth-callback.component'; 4 | 5 | describe('OauthCallbackComponent', () => { 6 | let component: OauthCallbackComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OauthCallbackComponent] 12 | }); 13 | fixture = TestBed.createComponent(OauthCallbackComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/password-reset/password-reset.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PasswordResetComponent } from './password-reset.component'; 4 | 5 | describe('PasswordResetComponent', () => { 6 | let component: PasswordResetComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [PasswordResetComponent] 12 | }); 13 | fixture = TestBed.createComponent(PasswordResetComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-rival-list/v2-rival-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { V2RivalListComponent } from './v2-rival-list.component'; 4 | 5 | describe('V2RivalListComponent', () => { 6 | let component: V2RivalListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2RivalListComponent] 12 | }); 13 | fixture = TestBed.createComponent(V2RivalListComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-festa/maimai2-festa.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Maimai2FestaComponent } from './maimai2-festa.component'; 4 | 5 | describe('Maimai2FestaComponent', () => { 6 | let component: Maimai2FestaComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2FestaComponent] 12 | }); 13 | fixture = TestBed.createComponent(Maimai2FestaComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-rival/maimai2-rival.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Maimai2RivalComponent } from './maimai2-rival.component'; 4 | 5 | describe('Maimai2RivalComponent', () => { 6 | let component: Maimai2RivalComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2RivalComponent] 12 | }); 13 | fixture = TestBed.createComponent(Maimai2RivalComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | RinNET 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/testing'; 4 | import {getTestBed} from '@angular/core/testing'; 5 | import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from '@angular/platform-browser-dynamic/testing'; 6 | 7 | declare const require: any; 8 | 9 | // First, initialize the Angular testing environment. 10 | getTestBed().initTestEnvironment( 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting(), { 13 | teardown: { destroyAfterEach: false } 14 | } 15 | ); 16 | // Then we find all the tests. 17 | const context = require.context('./', true, /\.spec\.ts$/); 18 | // And load the modules. 19 | context.keys().map(context); 20 | -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import {AppPage} from './app.po'; 2 | import {browser, logging} from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('aqua-viewer app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-circle/maimai2-circle.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Maimai2CircleComponent } from './maimai2-circle.component'; 4 | 5 | describe('Maimai2CircleComponent', () => { 6 | let component: Maimai2CircleComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2CircleComponent] 12 | }); 13 | fixture = TestBed.createComponent(Maimai2CircleComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-dxpass/maimai2-dxpass.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Maimai2DxpassComponent } from './maimai2-dxpass.component'; 4 | 5 | describe('Maimai2DxpassComponent', () => { 6 | let component: Maimai2DxpassComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2DxpassComponent] 12 | }); 13 | fixture = TestBed.createComponent(Maimai2DxpassComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-item/ongeki-card-item.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiCardItemComponent } from './ongeki-card-item.component'; 4 | 5 | describe('OngekiCardItemComponent', () => { 6 | let component: OngekiCardItemComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiCardItemComponent] 12 | }); 13 | fixture = TestBed.createComponent(OngekiCardItemComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/util/full-width.pipe.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"full-width.pipe.js","sourceRoot":"","sources":["full-width.pipe.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iBAoBA;;;AApBA,sCAAoD;AAKpD;4BAHC,IAAA,WAAI,EAAC;YACJ,IAAI,EAAE,WAAW;SAClB,CAAC;;;;QACW,aAAa;;QAc1B,CAAC;QAZC,mCAAS,GAAT,UAAU,KAAa;YACrB,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,UAAC,IAAI;gBAChC,IAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;gBAChC,IAAI,IAAI,KAAK,IAAI,EAAE;oBACjB,OAAO,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;iBACpC;qBAAM,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE;oBACvC,OAAO,MAAM,CAAC,YAAY,CAAC,IAAI,GAAG,MAAM,CAAC,CAAC;iBAC3C;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACd,CAAC;QAEH,sBAAC;IAAD,CAAC;;;QAdD,wJAcC;QAdY,aAAa;QAAb,uDAAa;;WAAb,aAAa;IAczB"} -------------------------------------------------------------------------------- /src/assets/github.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-songlist/maimai2-songlist.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Maimai2SonglistComponent } from './maimai2-songlist.component'; 4 | 5 | describe('Maimai2SonglistComponent', () => { 6 | let component: Maimai2SonglistComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2SonglistComponent] 12 | }); 13 | fixture = TestBed.createComponent(Maimai2SonglistComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-level/ongeki-card-level.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {AttributeType} from '../model/OngekiEnums'; 3 | import {environment} from '../../../../environments/environment'; 4 | 5 | @Component({ 6 | selector: 'app-ongeki-card-level', 7 | templateUrl: './ongeki-card-level.component.html', 8 | styleUrls: ['./ongeki-card-level.component.css'], 9 | inputs: ['level', 'attribute'] 10 | }) 11 | export class OngekiCardLevelComponent implements OnInit { 12 | 13 | protected readonly AttributeType = AttributeType; 14 | protected readonly Math = Math; 15 | host = environment.assetsHost; 16 | level: number; 17 | attribute: string; 18 | constructor() { } 19 | 20 | ngOnInit(): void { 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-song-detail/maimai2-song-detail.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { Maimai2SongDetailComponent } from './maimai2-song-detail.component'; 4 | 5 | describe('V2SongScoreRankingComponent', () => { 6 | let component: Maimai2SongDetailComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2SongDetailComponent] 12 | }); 13 | fixture = TestBed.createComponent(Maimai2SongDetailComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/styles/public.ranking.scss: -------------------------------------------------------------------------------- 1 | .ranking-row{ 2 | padding-left: 0.5em; 3 | } 4 | 5 | .medal { 6 | width: 2em; 7 | } 8 | 9 | .ranking-text { 10 | display: inline-block; 11 | width: 2rem; 12 | text-align: center; 13 | font-weight: bold; 14 | color: #7e7e7e; 15 | } 16 | 17 | .ranking-item-icon { 18 | width: 3em; 19 | aspect-ratio: 1; 20 | } 21 | 22 | .ranking-item-icon-lg { 23 | width: 4em !important; 24 | } 25 | 26 | .ranking-item-icon-xl { 27 | width: 5em !important; 28 | } 29 | 30 | th{ 31 | display: table-cell; 32 | vertical-align: middle; 33 | } 34 | 35 | td{ 36 | display: table-cell; 37 | vertical-align: middle; 38 | } 39 | 40 | //@media (min-width: 992px) { 41 | // table { 42 | // width: 70%; 43 | // } 44 | //} 45 | -------------------------------------------------------------------------------- /src/app/importer/importer/importer.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {ImporterComponent} from './importer.component'; 4 | 5 | describe('ImporterComponent', () => { 6 | let component: ImporterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ImporterComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ImporterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-song-score-ranking/v2-song-score-ranking.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { V2SongScoreRankingComponent } from './v2-song-score-ranking.component'; 4 | 5 | describe('V2SongScoreRankingComponent', () => { 6 | let component: V2SongScoreRankingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2SongScoreRankingComponent] 12 | }); 13 | fixture = TestBed.createComponent(V2SongScoreRankingComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/ChusanMusic.ts: -------------------------------------------------------------------------------- 1 | export interface ChusanMusic { 2 | musicId: number; 3 | name: string; 4 | sotrName: string; 5 | artistName: string; 6 | genre: string; 7 | releaseVersion: string; 8 | levels: ChusanMusicLevels; 9 | } 10 | 11 | export interface ChusanMusicLevels { 12 | 0: ChusanMusicLevelInfo; 13 | 1: ChusanMusicLevelInfo; 14 | 2: ChusanMusicLevelInfo; 15 | 3: ChusanMusicLevelInfo; 16 | 4: ChusanMusicLevelInfo; 17 | 5: ChusanMusicLevelInfo; 18 | } 19 | 20 | export interface ChusanMusicLevelInfo { 21 | enable: boolean; 22 | level: number; 23 | levelDecimal: number; 24 | diff: number; 25 | } 26 | 27 | export enum Difficulty { 28 | BASIC = 0, 29 | ADVANCED = 1, 30 | EXPERT = 2, 31 | MASTER = 3, 32 | ULTIMA = 4, 33 | 'WORLD\'S END' = 5, 34 | } 35 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-rating/v2-rating.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {V2RatingComponent} from './v2-rating.component'; 4 | 5 | describe('V2RatingComponent', () => { 6 | let component: V2RatingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2RatingComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2RatingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-recent/v2-recent.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {V2RecentComponent} from './v2-recent.component'; 4 | 5 | describe('V2RecentComponent', () => { 6 | let component: V2RecentComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2RecentComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2RecentComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-profile/v2-profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {V2ProfileComponent} from './v2-profile.component'; 4 | 5 | describe('V2ProfileComponent', () => { 6 | let component: V2ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2ProfileComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2ProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-level/ongeki-card-level.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiCardLevelComponent } from './ongeki-card-level.component'; 4 | 5 | describe('OngekiCardLevelComponent', () => { 6 | let component: OngekiCardLevelComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ OngekiCardLevelComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(OngekiCardLevelComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-setting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { V2SettingComponent } from './v2-setting.component'; 4 | 5 | describe('V2SettingComponent', () => { 6 | let component: V2SettingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ V2SettingComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2SettingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-userbox/v2-symbol-chat-setting/v2-symbol-chat-setting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { V2SymbolChatSettingComponent } from './v2-symbol-chat-setting.component'; 4 | 5 | describe('V2SymbolChatSettingComponent', () => { 6 | let component: V2SymbolChatSettingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2SymbolChatSettingComponent] 12 | }); 13 | fixture = TestBed.createComponent(V2SymbolChatSettingComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-userbox/v2-userbox.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import { V2UserBoxComponent } from './v2-userbox.component'; 4 | 5 | describe('V2UserBoxComponent', () => { 6 | let component: V2UserBoxComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ V2UserBoxComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2UserBoxComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-songlist/v2-songlist.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {V2SonglistComponent} from './v2-songlist.component'; 4 | 5 | describe('V2SonglistComponent', () => { 6 | let component: V2SonglistComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2SonglistComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2SonglistComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-recent-item/ongeki-recent-item.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiRecentItemComponent } from './ongeki-recent-item.component'; 4 | 5 | describe('OngekiRecentItemComponent', () => { 6 | let component: OngekiRecentItemComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ OngekiRecentItemComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(OngekiRecentItemComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-character/v2-character.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {V2CharacterComponent} from './v2-character.component'; 4 | 5 | describe('V2CharacterComponent', () => { 6 | let component: V2CharacterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [V2CharacterComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2CharacterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-song-score-ranking/ongeki-song-score-ranking.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiSongScroeRankingComponent } from './ongeki-song-scroe-ranking.component'; 4 | 5 | describe('OngekiSongScroeRankingComponent', () => { 6 | let component: OngekiSongScroeRankingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiSongScroeRankingComponent] 12 | }); 13 | fixture = TestBed.createComponent(OngekiSongScroeRankingComponent); 14 | component = fixture.componentInstance; 15 | fixture.detectChanges(); 16 | }); 17 | 18 | it('should create', () => { 19 | expect(component).toBeTruthy(); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/app/dashboard/dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 3 | 4 | import {DashboardComponent} from './dashboard.component'; 5 | 6 | describe('DashboardComponent', () => { 7 | let component: DashboardComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(waitForAsync(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [DashboardComponent] 13 | }) 14 | .compileComponents(); 15 | })); 16 | 17 | beforeEach(() => { 18 | fixture = TestBed.createComponent(DashboardComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-user-ranking/v2-user-ranking.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { V2UserRankingComponent } from './v2-user-ranking.component'; 4 | 5 | describe('V2UserRankingComponent', () => { 6 | let component: V2UserRankingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ V2UserRankingComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(V2UserRankingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-rating/ongeki-rating.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiRatingComponent} from './ongeki-rating.component'; 4 | 5 | describe('OngekiRatingComponent', () => { 6 | let component: OngekiRatingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiRatingComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiRatingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-recent/ongeki-recent.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiRecentComponent} from './ongeki-recent.component'; 4 | 5 | describe('OngekiRecentComponent', () => { 6 | let component: OngekiRecentComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiRecentComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiRecentComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-profile/ongeki-profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiProfileComponent} from './ongeki-profile.component'; 4 | 5 | describe('OngekiProfileComponent', () => { 6 | let component: OngekiProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiProfileComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-setting/ongeki-setting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiSettingComponent} from './ongeki-setting.component'; 4 | 5 | describe('OngekiSettingComponent', () => { 6 | let component: OngekiSettingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiSettingComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiSettingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-profile/maimai2-profile.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {Maimai2ProfileComponent} from './maimai2-profile.component'; 4 | 5 | describe('Maimai2ProfileComponent', () => { 6 | let component: Maimai2ProfileComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2ProfileComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(Maimai2ProfileComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-setting/maimai2-setting.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {Maimai2SettingComponent} from './maimai2-setting.component'; 4 | 5 | describe('Maimai2SettingComponent', () => { 6 | let component: Maimai2SettingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [Maimai2SettingComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(Maimai2SettingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-song-list/ongeki-song-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiSongListComponent} from './ongeki-song-list.component'; 4 | 5 | describe('OngekiSongListComponent', () => { 6 | let component: OngekiSongListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiSongListComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiSongListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-rival-list/ongeki-rival-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiRivalListComponent} from './ongeki-rival-list.component'; 4 | 5 | describe('OngekiRivalListComponent', () => { 6 | let component: OngekiRivalListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiRivalListComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiRivalListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-user-ranking/ongeki-user-ranking.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiUserRankingComponent } from './ongeki-user-ranking.component'; 4 | 5 | describe('OngekiUserRankingComponent', () => { 6 | let component: OngekiUserRankingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ OngekiUserRankingComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiUserRankingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/not-found/not-found.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-gallery/ongeki-card-gallery.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiCardGalleryComponent} from './ongeki-card-gallery.component'; 4 | 5 | describe('OngekiCardComponent', () => { 6 | let component: OngekiCardGalleryComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiCardGalleryComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiCardGalleryComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-music-ranking/ongeki-music-ranking.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OngekiMusicRankingComponent } from './ongeki-music-ranking.component'; 4 | 5 | describe('OngekiMusicRankingComponent', () => { 6 | let component: OngekiMusicRankingComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ OngekiMusicRankingComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiMusicRankingComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2Music.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2Music { 2 | musicId: number; 3 | name: string; 4 | artistName: string; 5 | sortName: string; 6 | genreId: number; 7 | romVersion: number; 8 | addVersion: number; 9 | details: Maimai2MusicDetails; 10 | } 11 | 12 | export interface Maimai2MusicDetails { 13 | 0: Maimai2MusicDetail; 14 | 1: Maimai2MusicDetail; 15 | 2: Maimai2MusicDetail; 16 | 3: Maimai2MusicDetail; 17 | 4: Maimai2MusicDetail; 18 | 5: Maimai2MusicDetail; 19 | } 20 | 21 | export interface Maimai2MusicDetail { 22 | id: number; 23 | tapCount: number; 24 | holdCount: number; 25 | breakCount: number; 26 | slideCount: number; 27 | touchCount: number; 28 | levelDecimal: number; 29 | noteDesigner: string; 30 | utageComment: string; 31 | utageKanji: string; 32 | tsuikaVersion: number; 33 | diff: number; 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-battle-point/ongeki-battle-point.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 2 | 3 | import {OngekiBattlePointComponent} from './ongeki-battle-point.component'; 4 | 5 | describe('OngekiBattlePointComponent', () => { 6 | let component: OngekiBattlePointComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(waitForAsync(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [OngekiBattlePointComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OngekiBattlePointComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/supportedBrowsers.ts: -------------------------------------------------------------------------------- 1 | export default 2 | /Edge?\/(9[7-9]|\d{3,})\.\d+(\.\d+|)|Firefox\/(9[5-9]|\d{3,})\.\d+(\.\d+|)|Chrom(ium|e)\/(9[7-9]|\d{3,})\.\d+(\.\d+|)|(Maci|X1{2}).+ Version\/(15\.([2-9]|\d{2,})|(1[6-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(8[2-9]|9\d|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(15[._]([2-9]|\d{2,})|(1[6-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](13[1-9]|1[4-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Mobile Safari.+OPR\/([89]\d|\d{3,})\.\d+\.\d+|Android.+Firefox\/(13[2-9]|1[4-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(13[1-9]|1[4-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+(UC? ?Browser|UCWEB|U3)[ /]?(15\.([5-9]|\d{2,})|(1[6-9]|[2-9]\d|\d{3,})\.\d+)\.\d+|SamsungBrowser\/(1[6-9]|[2-9]\d|\d{3,})\.\d+|Android.+MQ{2}Browser\/(14(\.(9|\d{2,})|)|(1[5-9]|[2-9]\d|\d{3,})(\.\d+|))(\.\d+|)/ 3 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-attribute-class.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toAttributeClass' 5 | }) 6 | export class ToAttributeClassPipe implements PipeTransform { 7 | 8 | transform(value: any): string { 9 | if (typeof value === 'string') { 10 | switch (value) { 11 | case 'Fire': 12 | return 'lv12'; 13 | case 'Aqua': 14 | return 'lv8'; 15 | case 'Leaf': 16 | return 'lv6'; 17 | case 'Max': 18 | return ''; 19 | } 20 | } 21 | if (typeof value === 'number') { 22 | switch (value) { 23 | // Start from 1 24 | case 1: 25 | return 'lv12'; 26 | case 2: 27 | return 'lv8'; 28 | case 3: 29 | return 'lv6'; 30 | case 4: 31 | return ''; 32 | } 33 | } 34 | return ''; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/rating-class.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'ratingClass' 5 | }) 6 | export class RatingClass implements PipeTransform { 7 | 8 | transform(s: number, args?: any): string { 9 | switch (true) { 10 | case (s >= 0.00 && s <= 3.99): 11 | return 'lv0'; 12 | case (s >= 4.00 && s <= 6.99): 13 | return 'lv6'; 14 | case (s >= 7.00 && s <= 9.99): 15 | return 'lv2'; 16 | case (s >= 10.00 && s <= 11.99): 17 | return 'lv12'; 18 | case (s >= 12.00 && s <= 13.24): 19 | return 'lv10'; 20 | case (s >= 13.25 && s <= 14.99): 21 | return 'lv14'; 22 | case (s >= 14.50 && s <= 15.24): 23 | return 'lv15'; 24 | case (s >= 15.25 && s <= 15.99): 25 | return 'lv16'; 26 | case (s >= 16.0): 27 | return 'lv17'; 28 | } 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/app/profile/profile.component.css: -------------------------------------------------------------------------------- 1 | .col-container{ 2 | display: flex; 3 | align-items: center; 4 | justify-content: space-between; 5 | gap: 1rem; 6 | } 7 | 8 | .col-content{ 9 | flex-grow: 1; 10 | align-items: center; 11 | justify-content: space-between; 12 | gap: .2rem; 13 | } 14 | 15 | .col-lead{ 16 | display: flex; 17 | align-items: center; 18 | font-size: small; 19 | --bs-text-opacity: 1; 20 | width: 8em; 21 | } 22 | 23 | .col-value{ 24 | font-weight: bold; 25 | font-size: small; 26 | overflow: hidden; 27 | width: 0em; 28 | } 29 | 30 | .col-action { 31 | flex: 0 1 auto; 32 | flex-shrink: 0; 33 | font-size: small; 34 | text-decoration: none; 35 | } 36 | 37 | .col-action:hover { 38 | text-decoration: underline; 39 | cursor: pointer; 40 | } 41 | 42 | .oauth-icon { 43 | height: 1.4em; 44 | width: 1.4em; 45 | margin-inline-end: .6em; 46 | color: var(--bs-body-color); 47 | } 48 | -------------------------------------------------------------------------------- /src/app/util/ordinal.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { TranslateService } from '@ngx-translate/core'; 3 | 4 | @Pipe({ 5 | name: 'ordinal' 6 | }) 7 | export class OrdinalPipe implements PipeTransform { 8 | 9 | constructor(private translateService: TranslateService) {} 10 | 11 | transform(value: number): string { 12 | const locale = this.translateService.currentLang; 13 | if (locale === 'en') { 14 | return this.getEnglishOrdinal(value); 15 | } 16 | return value.toString(); 17 | } 18 | 19 | private getEnglishOrdinal(value: number): string { 20 | const ordinalFormatter = new Intl.PluralRules('en', { type: 'ordinal' }); 21 | const suffixes = { 22 | one: 'st', 23 | two: 'nd', 24 | few: 'rd', 25 | other: 'th' 26 | }; 27 | const suffix = suffixes[ordinalFormatter.select(value)]; 28 | return `${value}${suffix}`; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-userbox/v2-symbol-chat-setting/v2-symbol-chat-setting.component.css: -------------------------------------------------------------------------------- 1 | .selected { 2 | border: 1px solid var(--bs-primary) !important; 3 | } 4 | 5 | .row > .item-card { 6 | box-sizing: border-box; 7 | padding: 1%; 8 | border-radius: 10px; 9 | border: 1px solid transparent; 10 | cursor: default; 11 | } 12 | 13 | .item-card img{ 14 | object-fit: contain; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | 19 | .item-container{ 20 | aspect-ratio: 1.8; 21 | width: 100%; 22 | max-height: 6em; 23 | display: flex; 24 | justify-content: center; 25 | } 26 | 27 | .item-body{ 28 | height: 100%; 29 | aspect-ratio: 1.5; 30 | position: relative; 31 | container: symbol-chat-container / size; 32 | } 33 | 34 | .item-text{ 35 | position: absolute; 36 | transform: translate(-50%, -50%); 37 | top: 50%; 38 | left: 50%; 39 | color: black; 40 | font-size: 10cqh; 41 | width: 70%; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | // apiServer: 'http://38.147.172.133/', 7 | // apiServer: 'http://192.168.123.112/', 8 | apiServer: '/', 9 | production: false, 10 | enableImages: true, 11 | assetsHost: 'https://rinnet.stehp.cn/' 12 | }; 13 | 14 | /* 15 | * For easier debugging in development mode, you can import the following file 16 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 17 | * 18 | * This import should be commented out in production mode because it will have a negative impact 19 | * on performance if an error is thrown. 20 | */ 21 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI. 22 | -------------------------------------------------------------------------------- /src/app/auth/account.service.ts: -------------------------------------------------------------------------------- 1 | import {BehaviorSubject} from 'rxjs'; 2 | import {Injectable} from '@angular/core'; 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class AccountService { 7 | private currentAccountSubject: BehaviorSubject; 8 | 9 | constructor() { 10 | this.currentAccountSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('currentAccount'))); 11 | } 12 | 13 | public get currentAccountValue(): Account { 14 | return this.currentAccountSubject.value; 15 | } 16 | 17 | public set currentAccountValue(account: Account) { 18 | localStorage.setItem('currentAccount', JSON.stringify(account)); 19 | this.currentAccountSubject.next(account); 20 | } 21 | 22 | public clear(){ 23 | localStorage.removeItem('currentAccount'); 24 | this.currentAccountSubject.next(null); 25 | } 26 | } 27 | 28 | export class Account { 29 | tokenType: string; 30 | accessToken: string; 31 | } 32 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-rating/v2-rating.component.scss: -------------------------------------------------------------------------------- 1 | .rating-info { 2 | font-size: 1.2em; 3 | } 4 | 5 | .jacket{ 6 | width: 5.6rem; 7 | aspect-ratio: 1; 8 | } 9 | 10 | .difficulty { 11 | font-size: 12px; 12 | } 13 | 14 | .difficulty-basic { 15 | background: #2da060; 16 | border: 1px solid #145830; 17 | color: white; 18 | } 19 | 20 | .difficulty-advanced { 21 | background: #e6a047; 22 | border: 1px solid #995014; 23 | color: white; 24 | } 25 | 26 | .difficulty-expert { 27 | background: #e55353; 28 | border: 1px solid #7B1F18; 29 | color: white; 30 | } 31 | 32 | .difficulty-master { 33 | background: #9d5cb9; 34 | border: 1px solid #381C47; 35 | color: white; 36 | } 37 | 38 | .difficulty-ultima { 39 | background: var(--bs-black); 40 | border: 1px solid #ff2855; 41 | color: #ff2855; 42 | } 43 | 44 | .rating-score { 45 | display: flex; 46 | align-items: center; 47 | b { 48 | padding: 0 3px; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const {SpecReporter} = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function () { 25 | } 26 | }, 27 | onPrepare() { 28 | require('ts-node').register({ 29 | project: require('path').join(__dirname, './tsconfig.json') 30 | }); 31 | jasmine.getEnv().addReporter(new SpecReporter({spec: {displayStacktrace: true}})); 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/app/contributors/contributors.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { ContributorsComponent } from './contributors.component'; 7 | 8 | describe('ContributorsComponent', () => { 9 | let component: ContributorsComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ ContributorsComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(ContributorsComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/importer/importer.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {CommonModule} from '@angular/common'; 3 | import {ImporterComponent} from './importer/importer.component'; 4 | import {FormsModule, ReactiveFormsModule} from '@angular/forms'; 5 | import {TranslateModule, TranslateLoader } from '@ngx-translate/core'; 6 | import {TranslateHttpLoader } from '@ngx-translate/http-loader'; 7 | import {HttpClient } from '@angular/common/http'; 8 | 9 | export function HttpLoaderFactory(http: HttpClient) { 10 | return new TranslateHttpLoader(http); 11 | } 12 | 13 | @NgModule({ 14 | declarations: [ImporterComponent], 15 | imports: [ 16 | CommonModule, 17 | ReactiveFormsModule, 18 | FormsModule, TranslateModule.forChild({ 19 | loader: { 20 | provide: TranslateLoader, 21 | useFactory: HttpLoaderFactory, 22 | deps: [HttpClient] 23 | } 24 | }) 25 | ] 26 | }) 27 | export class ImporterModule { 28 | } 29 | -------------------------------------------------------------------------------- /src/app/message.service.ts: -------------------------------------------------------------------------------- 1 | import {MessageComponent} from './message/message.component'; 2 | import {Injectable} from '@angular/core'; 3 | import {ToastService} from "./toast-service"; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class MessageService { 9 | constructor(private messageComponent: MessageComponent, 10 | public toastService: ToastService) { 11 | } 12 | 13 | notice(message: string, color: 'danger' | 'warning' | 'success' = null) { 14 | if(color === 'danger'){ 15 | this.toastService.show(message, {classname: 'text-bg-danger'}); 16 | } 17 | else if(color === 'warning'){ 18 | this.toastService.show(message, {classname: 'text-bg-warning'}); 19 | } 20 | else if(color === 'success'){ 21 | this.toastService.show(message, {classname: 'text-bg-success'}); 22 | } 23 | else{ 24 | this.toastService.show(message); 25 | } 26 | // this.messageComponent.openSnackBar(message); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/assets/mai2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2GameFesta.ts: -------------------------------------------------------------------------------- 1 | export interface Maimai2GameFesta { 2 | 3 | name: string; 4 | 5 | collaboration: number; 6 | 7 | seasonNum: number; 8 | 9 | festaTitle: string; 10 | 11 | festaSide01: string; 12 | 13 | festaSide02: string; 14 | 15 | festaSide03: string; 16 | 17 | musicClearPoint: number; 18 | 19 | rallyPoint1st: number; 20 | 21 | rallyPoint2nd: number; 22 | 23 | rallyPoint3rd: number; 24 | 25 | bonusPoint2p: number; 26 | 27 | daliyBonus: number; 28 | 29 | rewardBorder: number; 30 | 31 | rewardType: number; 32 | 33 | rewardId: number; 34 | 35 | openEventId: string; 36 | 37 | resultEventId: string; 38 | 39 | themeInfoFile: string; 40 | 41 | rewardInfoFile: string; 42 | 43 | netOpenName: string; 44 | 45 | releaseTagName: string; 46 | 47 | finalResultFile: string; 48 | 49 | rightFile: string; 50 | 51 | priority: number; 52 | 53 | dataName: string; 54 | 55 | festaPhaseState: string; 56 | } 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | .vscode/ 4 | 5 | # compiled output 6 | /dist 7 | /tmp 8 | /out-tsc 9 | # Only exists if Bazel was run 10 | /bazel-out 11 | 12 | # dependencies 13 | /node_modules 14 | 15 | # profiling files 16 | chrome-profiler-events*.json 17 | speed-measure-plugin*.json 18 | 19 | # IDEs and editors 20 | /.idea 21 | .project 22 | .classpath 23 | .c9/ 24 | *.launch 25 | .settings/ 26 | *.sublime-workspace 27 | 28 | # IDE - VSCode 29 | .vscode/* 30 | !.vscode/settings.json 31 | !.vscode/tasks.json 32 | !.vscode/launch.json 33 | !.vscode/extensions.json 34 | .history/* 35 | 36 | # misc 37 | /.angular/cache 38 | /.sass-cache 39 | /connect.lock 40 | /coverage 41 | /libpeerconnection.log 42 | npm-debug.log 43 | yarn-error.log 44 | testem.log 45 | /typings 46 | 47 | # System Files 48 | .DS_Store 49 | Thumbs.db 50 | 51 | # assets 52 | /src/assets/ongeki 53 | /src/assets/chuni 54 | /.vs 55 | /src/assets/mai2 56 | /src/assets/mai2 57 | -------------------------------------------------------------------------------- /src/app/message/message.component.spec.ts: -------------------------------------------------------------------------------- 1 | import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; 2 | import {MessageModule} from './message.module'; 3 | /* tslint:disable:no-unused-variable */ 4 | import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; 5 | 6 | import {MessageComponent} from './message.component'; 7 | 8 | describe('MessageComponent', () => { 9 | let component: MessageComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(waitForAsync(() => { 13 | TestBed.configureTestingModule({ 14 | imports: [ 15 | MessageModule, 16 | BrowserAnimationsModule, 17 | ] 18 | }) 19 | .compileComponents(); 20 | })); 21 | 22 | beforeEach(() => { 23 | fixture = TestBed.createComponent(MessageComponent); 24 | component = fixture.componentInstance; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2PlayLog.ts: -------------------------------------------------------------------------------- 1 | import {ChusanMusic} from './ChusanMusic'; 2 | 3 | export interface V2PlayLog { 4 | playDate: Date; 5 | userPlayDate: Date; 6 | musicId: number; 7 | songInfo?: ChusanMusic; 8 | level: number; 9 | customId: number; 10 | playedCustom1: number; 11 | playedCustom2: number; 12 | playedCustom3: number; 13 | track: number; 14 | score: number; 15 | rank: number; 16 | maxCombo: number; 17 | maxChain: number; 18 | rateTap: number; 19 | rateHold: number; 20 | rateSlide: number; 21 | rateAir: number; 22 | rateFlick: number; 23 | judgeGuilty: number; 24 | judgeAttack: number; 25 | judgeJustice: number; 26 | judgeCritical: number; 27 | judgeHeaven: number; 28 | playerRating: number; 29 | fullChainKind: number; 30 | characterId: number; 31 | skillId: number; 32 | playKind: number; 33 | skillLevel: number; 34 | skillEffect: number; 35 | isNewRecord: boolean; 36 | isFullCombo: boolean; 37 | isAllJustice: boolean; 38 | isClear: boolean; 39 | } 40 | -------------------------------------------------------------------------------- /src/app/auth/admin-guard.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot} from '@angular/router'; 3 | import {AccountService} from './account.service'; 4 | import {UserService} from '../user.service'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class AdminGuardService implements CanLoad, CanActivate { 10 | 11 | constructor( 12 | private router: Router, 13 | protected user: UserService) { 14 | } 15 | 16 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 17 | if (this.isAdmin()) { 18 | return true; 19 | } 20 | 21 | this.router.navigate(['/dashboard']); 22 | return false; 23 | } 24 | 25 | canLoad(route: Route) { 26 | if (this.isAdmin()) { 27 | return true; 28 | } 29 | 30 | this.router.navigate(['/dashboard']); 31 | return false; 32 | } 33 | 34 | isAdmin() { 35 | return this.user.currentUser?.roles?.some(r => r.id === 5) ?? false; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/app/auth/error-interceptor.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http'; 3 | import {Observable, throwError} from 'rxjs'; 4 | import {catchError} from 'rxjs/operators'; 5 | import {AccountService} from './account.service'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class ErrorInterceptorService implements HttpInterceptor { 11 | 12 | constructor( 13 | private accountService: AccountService) { 14 | } 15 | 16 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 17 | return next.handle(request).pipe(catchError(err => { 18 | console.log(err); 19 | const error = err.error.message ? err.error.message : `${err.status} ${err.statusText}`; 20 | if (err.status === 401 && this.accountService.currentAccountValue) 21 | { 22 | this.accountService.clear(); 23 | location.reload(); 24 | } 25 | return throwError(error); 26 | })); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/app/auth/login-guard.service.ts: -------------------------------------------------------------------------------- 1 | import { AccountService } from 'src/app/auth/account.service'; 2 | import { Injectable } from '@angular/core'; 3 | import { ActivatedRouteSnapshot, CanActivate, CanLoad, Route, Router, RouterStateSnapshot } from '@angular/router'; 4 | 5 | @Injectable({ 6 | providedIn: 'root' 7 | }) 8 | export class LoginGuardService implements CanLoad, CanActivate { 9 | 10 | constructor( 11 | private router: Router, 12 | private accountService: AccountService 13 | ) { 14 | } 15 | 16 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 17 | const currentUser = this.accountService.currentAccountValue; 18 | if (!currentUser) { 19 | return true; 20 | } 21 | 22 | this.router.navigate(['/dashboard']); 23 | return false; 24 | } 25 | 26 | canLoad(route: Route) { 27 | const currentUser = this.accountService.currentAccountValue; 28 | if (!currentUser) { 29 | return true; 30 | } 31 | 32 | this.router.navigate(['/dashboard']); 33 | return false; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AquaViewer For RinNET 2 | 3 | This is the WebUI for RinNET, a fork of Aqua-Viewer. 4 | 5 | RinNET differs significantly from Aqua, additional development may be required to use it on your own server. 6 | 7 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli). 8 | 9 | ## Develop with CDN 10 | 11 | - Change `proxy.conf.json` if needed 12 | - Launch the development server with the command:
`$ npm run start ` 13 | - Visit [https://portal-dev.naominet.live](https://portal-dev.naominet.live). 14 | 15 | ## How to Contribute 16 | 17 | You can write code, test it yourself, and submit a pull request. You can also improve translations [here](/src/assets/i18n). 18 | 19 | Please follow the [deployment guide](https://angular.io/guide/deployment) if you are new to angular. 20 | 21 | ## License 22 | This project is governed by the AGPL-3.0 license. Should you employ or refer to the codebase of this project in delivering services to users, you are required to release your contributions under a license that is compatible with AGPL-3.0. 23 | -------------------------------------------------------------------------------- /ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/service-worker/config/schema.json", 3 | "index": "/index.html", 4 | "assetGroups": [ 5 | { 6 | "name": "app", 7 | "installMode": "prefetch", 8 | "resources": { 9 | "files": [ 10 | "/favicon.ico", 11 | "/index.html", 12 | "/manifest.webmanifest", 13 | "/*.css", 14 | "/*.js" 15 | ] 16 | } 17 | }, 18 | { 19 | "name": "assets", 20 | "installMode": "lazy", 21 | "updateMode": "prefetch", 22 | "resources": { 23 | "files": [ 24 | "/assets/**", 25 | "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani|wav)" 26 | ] 27 | } 28 | } 29 | ], 30 | "dataGroups": [ 31 | { 32 | "name": "api", 33 | "urls": [ 34 | "/api/**" 35 | ], 36 | "cacheConfig": { 37 | "strategy": "performance", 38 | "maxSize": 0, 39 | "maxAge": "0s", 40 | "timeout": "86400s" 41 | } 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /ssl/naominet.live.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICtzCCAZ8CFFNWx/sAIHugh7Q6GHwRkXvpHEEKMA0GCSqGSIb3DQEBCwUAMBYx 3 | FDASBgNVBAMMC0xvY2FsUm9vdENBMB4XDTI0MDQwMzAxMzM1MFoXDTM0MDIxMDAx 4 | MzM1MFowGjEYMBYGA1UEAwwPKi5uYW9taW5ldC5saXZlMIIBIjANBgkqhkiG9w0B 5 | AQEFAAOCAQ8AMIIBCgKCAQEAya375pbKZsWqDtklz7eeW+bTPuI9RwYJTCw1vDuP 6 | dHjC4ciPzst0SJfmrJZOGyKL0sObrlCdpRcVJ219h/fE/RgLWiNwbm5I2GhtfxdJ 7 | qviDCfnfJp2b+FsIoIBThiXz7PKh+/wFKcChcJWYG0o0L/8E+M2j89L+kCcWMxUt 8 | ExweMfZ0joxMq3UxwjqT1wHBIccyzPvtBJsLKvKZDsQ0El12zNNggn+J4UwlZZDk 9 | iIHMlFR5j2d+uEvrT2YPddTytgJEiDPT4fg+bK2z8MZIcl15ETChOwa9xSkl774T 10 | c/Vjw7IHd1cxfVzqKoPH4xJX7Gf2iz/ny2foJLsm9EJeqQIDAQABMA0GCSqGSIb3 11 | DQEBCwUAA4IBAQCosPCIu3S1ZFzAE+2uNonnMceXxr18++HLj20nS1hyAsIUaqhV 12 | kg9DcS6zQsLChA8kfBclmLXLLWHZPVBvFCwUjJOc/jATGyq2FAtyg3rLFfGl9ukF 13 | 2ioTXCZnkhCLE4Qw3sl9J8lWw3UkSTcgNdMHsHHDHqQQMrJGL0WyNZwiQkxjvx9l 14 | YkFaIM5u5uR+bhoYLX6QAh/vKTEueRTJcDgO/j4dezbwRk5oNhzHrKxZ36AtIjMB 15 | pjsUZQFL3m9eBN5HBjqGqJyYlXHMxR+SMJhotC8yA+I7Dk/p3fzp5wDRsCx+NfFf 16 | 2nTfJmB+CV8vV6d0pPAgO/T7nW7sX/Xz+w8x 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-rank.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toRank' 5 | }) 6 | export class ToRankPipe implements PipeTransform { 7 | 8 | transform(value: number): string { 9 | if (value === 0) { 10 | return 'D'; 11 | } 12 | if (value === 1) { 13 | return 'C'; 14 | } 15 | if (value === 2) { 16 | return 'B'; 17 | } 18 | if (value === 3) { 19 | return 'BB'; 20 | } 21 | if (value === 4) { 22 | return 'BBB'; 23 | } 24 | if (value === 5) { 25 | return 'A'; 26 | } 27 | if (value === 6) { 28 | return 'AA'; 29 | } 30 | if (value === 7) { 31 | return 'AAA'; 32 | } 33 | if (value === 8) { 34 | return 'S'; 35 | } 36 | if (value === 9) { 37 | return 'S+'; 38 | } 39 | if (value === 10) { 40 | return 'SS'; 41 | } 42 | if (value === 11) { 43 | return 'SS+'; 44 | } 45 | if (value === 12) { 46 | return 'SSS'; 47 | } 48 | if (value > 12) { 49 | return 'SSS+'; 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/app/importer/importer/importer.component.html: -------------------------------------------------------------------------------- 1 |

{{'ImportPage.Title' | translate}}

2 | 3 |
4 |
5 | {{'ImportPage.WarningTitle' | translate}} 6 |
7 |
8 | {{'ImportPage.WarningContent' | translate}} 9 |
10 |
11 | 12 |
13 |
14 | {{'Common.Ongeki' | translate}} 15 |
16 |
17 | 18 |
19 |
20 | 21 |
22 |
23 | {{'Common.ChuniV2' | translate}} 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | {{'Common.Mai2' | translate}} 33 |
34 |
35 | 36 |
37 |
38 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-gallery/ongeki-card-gallery.component.css: -------------------------------------------------------------------------------- 1 | .btn-top { 2 | width: 5em; 3 | } 4 | 5 | .cards-col { 6 | width: 100%; 7 | perspective: 1500px; 8 | transform-style: preserve-3d; 9 | --rotator-transition: all .6s ease-out; 10 | 11 | --rotator-global-rotate-y: 0deg; 12 | --rotator-rotate-x: 0deg; 13 | --rotator-rotate-y: 0deg; 14 | --pseudo-opacity: 0; 15 | --pseudo-left: 50%; 16 | --pseudo-top: 50%; 17 | 18 | --holo-sheet-bottom: none; 19 | --holo-sheet-middle: none; 20 | --holo-sheet-top: none; 21 | } 22 | 23 | .card-picking { 24 | --rotator-global-rotate-y: 360deg; 25 | } 26 | 27 | .card-backdrop { 28 | position: fixed; 29 | width: 100%; 30 | height: 100%; 31 | background: black; 32 | opacity: .8; 33 | top: 0; 34 | left: 0; 35 | z-index: 1099; 36 | transition: opacity 1s linear; 37 | visibility: visible; 38 | } 39 | 40 | .card-backdrop-hidden { 41 | visibility: hidden; 42 | opacity: .0; 43 | transition: opacity 1s linear, visibility 0s linear 1s; 44 | } 45 | 46 | .card-details-table{ 47 | 48 | } 49 | 50 | .card-details-table td{ 51 | width: 50%; 52 | } 53 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-battle-point/ongeki-battle-point.component.css: -------------------------------------------------------------------------------- 1 | .jacket{ 2 | width: 5.6rem; 3 | aspect-ratio: 1; 4 | } 5 | 6 | .difficulty { 7 | font-size: 12px; 8 | } 9 | 10 | .difficulty-basic { 11 | background: #2da060; 12 | border: 1px solid #145830; 13 | color: white; 14 | } 15 | 16 | .difficulty-advanced { 17 | background: #e6a047; 18 | border: 1px solid #995014; 19 | color: white; 20 | } 21 | 22 | .difficulty-expert { 23 | background: #e55353; 24 | border: 1px solid #7B1F18; 25 | color: white; 26 | } 27 | 28 | .difficulty-master { 29 | background: #9d5cb9; 30 | border: 1px solid #381C47; 31 | color: white; 32 | } 33 | 34 | .difficulty-lunatic { 35 | background: var(--bs-white); 36 | border: 1px solid var(--bs-danger); 37 | color: var(--bs-danger); 38 | } 39 | 40 | .attr-aqua { 41 | background: #1399dc; 42 | border: 1px solid #064488; 43 | color: white; 44 | } 45 | 46 | .attr-leaf { 47 | background: #00c122; 48 | border: 1px solid #005810; 49 | color: white; 50 | } 51 | 52 | .attr-fire { 53 | background: #e22f5d; 54 | border: 1px solid #701020; 55 | color: white; 56 | } 57 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, waitForAsync } from '@angular/core/testing'; 2 | import {AppComponent} from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(waitForAsync(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.debugElement.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'aqua-viewer'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.debugElement.componentInstance; 22 | expect(app.title).toEqual('aqua-viewer'); 23 | }); 24 | 25 | it('should render title', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('.content span').textContent).toContain('aqua-viewer app is running!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/aqua-viewer'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/app/auth/token-interceptor.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import { 3 | HttpRequest, 4 | HttpHandler, 5 | HttpEvent, 6 | HttpInterceptor 7 | } from '@angular/common/http'; 8 | import {Observable} from 'rxjs'; 9 | import {environment} from 'src/environments/environment'; 10 | import {AccountService} from './account.service'; 11 | @Injectable() 12 | export class TokenInterceptorService implements HttpInterceptor { 13 | constructor( 14 | private accountService: AccountService) { 15 | } 16 | intercept(request: HttpRequest, next: HttpHandler): Observable> { 17 | if ( 18 | request.url.startsWith(environment.apiServer) && 19 | this.accountService.currentAccountValue && 20 | this.accountService.currentAccountValue.tokenType && 21 | this.accountService.currentAccountValue.accessToken){ 22 | request = request.clone({ 23 | setHeaders: { 24 | Authorization: `${this.accountService.currentAccountValue.tokenType} ${this.accountService.currentAccountValue.accessToken}` 25 | } 26 | }); 27 | } 28 | return next.handle(request); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-card-level/ongeki-card-level.component.html: -------------------------------------------------------------------------------- 1 |
3 |
4 | 6 | 8 | 12 | 16 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /src/app/dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input } from '@angular/core'; 2 | import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; 3 | 4 | export interface DialogCustomModel { 5 | title: string; 6 | message: string; 7 | yesContent: string; 8 | noContent: string; 9 | yesClass: string; 10 | noClass: string; 11 | } 12 | 13 | @Component({ 14 | selector: 'app-dialog', 15 | template: ` 16 | 19 | 26 | 30 | ` 31 | }) 32 | export class DialogComponent { 33 | customModel: DialogCustomModel = null; 34 | constructor(public activeModal: NgbActiveModal) { } 35 | } -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-song-score-ranking/v2-song-score-ranking.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../../../../../node_modules/bootstrap/scss/bootstrap-grid"; 2 | 3 | .offcanvas { 4 | width: 40vw !important; 5 | } 6 | 7 | .music-img { 8 | width: 60%; 9 | } 10 | 11 | .fbab-img { 12 | margin-left: 20px; 13 | } 14 | 15 | .honor-badge { 16 | aspect-ratio: 1; 17 | width: 32px; 18 | } 19 | 20 | @include media-breakpoint-down(sm) { 21 | .music-img { 22 | width: 100%; 23 | } 24 | } 25 | 26 | .color-basic { 27 | color: #00ab84; 28 | } 29 | 30 | .color-advanced { 31 | color: #ff7e00; 32 | } 33 | 34 | .color-expert { 35 | color: #f12929; 36 | } 37 | 38 | .color-master { 39 | color: #8e1be5; 40 | } 41 | 42 | .color-ultima { 43 | color: #424242; 44 | } 45 | 46 | .color-we { 47 | background: linear-gradient(45deg, #0BE9EE, #ACE559, #FCE116, #CB00B0); 48 | -webkit-background-clip: text; 49 | -webkit-text-fill-color: transparent; 50 | font-weight: bold; 51 | -webkit-text-stroke: 1px rgba(0, 0, 0, 0.3); 52 | } 53 | 54 | .honor{ 55 | height: 32px; 56 | } 57 | 58 | .difficulty-detail-body{ 59 | min-height: 32px; 60 | } 61 | 62 | .medal { 63 | width: 1rem; 64 | } 65 | -------------------------------------------------------------------------------- /ssl/LocalRootCA.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDDTCCAfWgAwIBAgIUYwlx1hdjaTCTYGB8bzPB12cRsOowDQYJKoZIhvcNAQEL 3 | BQAwFjEUMBIGA1UEAwwLTG9jYWxSb290Q0EwHhcNMjQwNDAzMDEyMTE1WhcNMzQw 4 | NDAxMDEyMTE1WjAWMRQwEgYDVQQDDAtMb2NhbFJvb3RDQTCCASIwDQYJKoZIhvcN 5 | AQEBBQADggEPADCCAQoCggEBANMfeILcZZzd3ZaBybQtjXkkcDjXouYJYUZV7hvY 6 | XcMFCd6Xyfg69JM5y+8ukRhSZsES0Tlu4eP2Jpd9UqKrjgKRhthNvHS7ZIWhOSt0 7 | cHSp931cg5/gPrwmSXOAnWuzO0M9uG3eD2HDes2+SJvWiODq2IKfpJ1mnIbNgWGn 8 | upH38s+DPL2UwJo89VGSJMQsOKeQqd5bpBb2AOLEcfYDwrBlPQeBAggN1J5c9wkI 9 | rVJeKmSYKeZQ7+sB3HALrzHm9FT25JYsNWvbsoSjRst8b0kNWATFxMuZ0SESW23L 10 | YOzf+YHZoHrf7eFE0KvwL7UjQ/L0q30xj9+mPc7KOkNG65kCAwEAAaNTMFEwHQYD 11 | VR0OBBYEFFoiM+d18TmYVnxl1mGCjWMgemiQMB8GA1UdIwQYMBaAFFoiM+d18TmY 12 | Vnxl1mGCjWMgemiQMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB 13 | ABou5wtPu+m6A0K+2ga02CXRBEtB/JzqnkC2Oh7rPW0SY3WBbpVPY4qE6sdMfJBX 14 | znUSx4ZuEii4KGN9G55Y/UrZwiIMA4gf/Na4ILG/zqjJ+qy4PZABh3STaHrpSHjp 15 | sAmQAvbgsWVRuovQ5dzYYDGnwOtK1l7eJzncDx9pi9Sze0kXZuFBXskYzM9KFRPf 16 | 3Lk3ugYW3vZBTmGte2CzOwtfwEUsW7UspsbcZzAFUMnlEAKWgaaelEQSIz4M5G59 17 | wnib1IiZqJ56iGkSH7XeAQAeM6uayNQrhul7DMtZsaDacaynqLyGuugJUscSL90P 18 | mUlEQOP+grw2j82Axk85YIk= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /src/app/toasts-container.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, TemplateRef } from '@angular/core'; 2 | 3 | import { ToastService } from './toast-service'; 4 | import { NgFor, NgIf, NgTemplateOutlet } from '@angular/common'; 5 | import { NgbToastModule } from '@ng-bootstrap/ng-bootstrap'; 6 | 7 | @Component({ 8 | selector: 'app-toasts', 9 | standalone: true, 10 | imports: [NgbToastModule, NgIf, NgTemplateOutlet, NgFor], 11 | template: ` 12 | 19 | 20 | 21 | 22 | 23 | {{ toast.textOrTpl }} 24 | 25 | `, 26 | host: { class: 'toast-container position-fixed top-0 end-0 p-3', style: 'z-index: 1200' }, 27 | }) 28 | export class ToastsContainer { 29 | constructor(public toastService: ToastService) {} 30 | 31 | isTemplate(toast) { 32 | return toast.textOrTpl instanceof TemplateRef; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/app/dialog.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; 3 | import { DialogComponent, DialogCustomModel } from './dialog.component'; 4 | 5 | @Injectable({ providedIn: 'root' }) 6 | export class DialogService { 7 | constructor(private modalService: NgbModal) { } 8 | 9 | showCustom(customModel: DialogCustomModel): Promise { 10 | if (!customModel.yesContent) 11 | customModel.yesContent = "确定"; 12 | if (!customModel.noContent) 13 | customModel.noContent = "取消"; 14 | if (!customModel.yesClass) 15 | customModel.yesClass = "btn-primary"; 16 | if (!customModel.noClass) 17 | customModel.noClass = "btn-secondary"; 18 | 19 | const modalRef = this.modalService.open(DialogComponent, { centered: true }); 20 | modalRef.componentInstance.customModel = customModel; 21 | 22 | return modalRef.result.catch(() => false); 23 | } 24 | 25 | show(title: string, message: string): Promise { 26 | return this.showCustom({ title, message, yesClass: null, yesContent: null, noClass: null, noContent: null }); 27 | } 28 | } -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-tech-sprite.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | import {TechnicalRank} from '../model/OngekiEnums'; 3 | 4 | @Pipe({ 5 | name: 'toTechSprite' 6 | }) 7 | export class ToTechSpritePipe implements PipeTransform { 8 | 9 | transform(value: number): string { 10 | switch (TechnicalRank[value]) { 11 | case 'D': 12 | return 'SB_RES_ScoreRank_D.webp'; 13 | case 'C': 14 | return 'SB_RES_ScoreRank_C.webp'; 15 | case 'B': 16 | return 'SB_RES_ScoreRank_B.webp'; 17 | case 'BB': 18 | return 'SB_RES_ScoreRank_BB.webp'; 19 | case 'BBB': 20 | return 'SB_RES_ScoreRank_BBB.webp'; 21 | case 'A': 22 | return 'SB_RES_ScoreRank_A.webp'; 23 | case 'AA': 24 | return 'SB_RES_ScoreRank_AA.webp'; 25 | case 'AAA': 26 | return 'SB_RES_ScoreRank_AAA.webp'; 27 | case 'S': 28 | return 'SB_RES_ScoreRank_S.webp'; 29 | case 'SS': 30 | return 'SB_RES_ScoreRank_SS.webp'; 31 | case 'SSS': 32 | return 'SB_RES_ScoreRank_SSS.webp'; 33 | case 'SSS1': 34 | return 'SB_RES_ScoreRank_SSS%2B.webp'; 35 | } 36 | return null; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/auth/loading-interceptor.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ApiService } from '../api.service'; 3 | import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; 4 | import {finalize, Observable} from 'rxjs'; 5 | import { tap } from 'rxjs/operators'; 6 | 7 | @Injectable({ 8 | providedIn: 'root' 9 | }) 10 | export class LoadingInterceptorService implements HttpInterceptor { 11 | private activeRequests = 0; 12 | 13 | constructor(private api: ApiService) {} 14 | 15 | intercept(req: HttpRequest, next: HttpHandler): Observable> { 16 | if (this.activeRequests === 0) { 17 | this.showLoader(); 18 | } 19 | 20 | this.activeRequests++; 21 | 22 | return next.handle(req).pipe( 23 | finalize(() => { 24 | this.decrementActiveRequests(); 25 | }) 26 | ); 27 | } 28 | 29 | private decrementActiveRequests(): void { 30 | this.activeRequests--; 31 | 32 | if (this.activeRequests === 0) { 33 | this.hideLoader(); 34 | } 35 | } 36 | 37 | private showLoader(): void { 38 | this.api.show(); 39 | } 40 | 41 | private hideLoader(): void { 42 | this.api.hide(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/assets/ongeki.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 12 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-name-setting/v2-name-setting.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-rating/maimai2-rating.component.scss: -------------------------------------------------------------------------------- 1 | .rating-info { 2 | font-size: 1.2em; 3 | } 4 | 5 | .jacket{ 6 | width: 5.6rem; 7 | aspect-ratio: 1; 8 | } 9 | 10 | .difficulty { 11 | font-size: 12px; 12 | } 13 | 14 | .difficulty-basic { 15 | background: #2da060; 16 | border: 1px solid #145830; 17 | color: white; 18 | } 19 | 20 | .difficulty-advanced { 21 | background: #e6a047; 22 | border: 1px solid #995014; 23 | color: white; 24 | } 25 | 26 | .difficulty-expert { 27 | background: #e55353; 28 | border: 1px solid #7B1F18; 29 | color: white; 30 | } 31 | 32 | .difficulty-master { 33 | background: #933daa; 34 | border: 1px solid #381C47; 35 | color: white; 36 | } 37 | 38 | .difficulty-remaster { 39 | background: whitesmoke; 40 | border: 1px solid #381C47; 41 | color: #933daa; 42 | } 43 | 44 | .score-preview { 45 | background: #9d5cb9; 46 | border-radius: 1rem; 47 | color: white; 48 | } 49 | 50 | .your-maimai-rating-text{ 51 | margin-right:3px; 52 | } 53 | 54 | .rank-icon { 55 | height: 2rem; 56 | width: auto 57 | } 58 | 59 | :host-context([data-bs-theme="light"]) .player-rating { 60 | color: #323232; 61 | } 62 | 63 | :host-context([data-bs-theme=dark]) .player-rating { 64 | color: #d2d2d2; 65 | } -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-battle-sprite.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | import {BattleRank} from '../model/OngekiEnums'; 3 | 4 | @Pipe({ 5 | name: 'toBattleSprite' 6 | }) 7 | export class ToBattleSpritePipe implements PipeTransform { 8 | 9 | 10 | transform(value: number): string { 11 | switch (BattleRank[value]) { 12 | case 'Yu': 13 | return 'SB_RES_ScoreStamp_Great.webp'; 14 | case 'Ryo': 15 | return 'SB_RES_ScoreStamp_Good.webp'; 16 | case 'Fuka': 17 | return 'SB_RES_ScoreStamp_NoGood.webp'; 18 | case 'Shu': 19 | return 'SB_RES_ScoreStamp_Excellent.webp'; 20 | case 'Ka': 21 | return 'SB_RES_ScoreStamp_Usually.webp'; 22 | case 'Goku': 23 | return 'SB_RES_ScoreStamp_Unbelievable.webp'; 24 | case 'Goku1': 25 | return 'SB_RES_ScoreStamp_Unbelievable.webp'; 26 | case 'Goku2': 27 | return 'SB_RES_ScoreStamp_Unbelievable.webp'; 28 | case 'Goku3': 29 | return 'SB_RES_ScoreStamp_Unbelievable.webp'; 30 | case 'Goku4': 31 | return 'SB_RES_ScoreStamp_Unbelievable.webp'; 32 | case 'Goku5': 33 | return 'SB_RES_ScoreStamp_Unbelievable.webp'; 34 | } 35 | return null; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/app/auth/auth-guard.service.ts: -------------------------------------------------------------------------------- 1 | import {AccountService} from 'src/app/auth/account.service'; 2 | import {Injectable} from '@angular/core'; 3 | import { 4 | CanLoad, 5 | CanActivate, 6 | ActivatedRouteSnapshot, 7 | Router, 8 | RouterStateSnapshot, 9 | Route, 10 | CanMatch, 11 | UrlSegment, 12 | UrlTree 13 | } from '@angular/router'; 14 | import {Observable} from 'rxjs'; 15 | 16 | @Injectable({ 17 | providedIn: 'root' 18 | }) 19 | export class AuthGuardService implements CanMatch, CanActivate { 20 | 21 | constructor( 22 | private router: Router, 23 | private accountService: AccountService 24 | ) { 25 | } 26 | 27 | canMatch(route: Route, segments: UrlSegment[]): boolean | UrlTree | Observable | Promise { 28 | const currentUser = this.accountService.currentAccountValue; 29 | if (currentUser) { 30 | return true; 31 | } 32 | 33 | this.router.navigate(['/']); 34 | return false; 35 | } 36 | 37 | canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { 38 | const currentUser = this.accountService.currentAccountValue; 39 | if (currentUser) { 40 | return true; 41 | } 42 | this.router.navigate(['/']); 43 | return false; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/language.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { TranslateService } from '@ngx-translate/core'; 3 | 4 | @Injectable({ 5 | providedIn: 'root' 6 | }) 7 | export class LanguageService { 8 | public languages = new Map([ 9 | ['en', 'English'], 10 | ['zh', '简体中文'] 11 | ]); 12 | public languageKeys: string[] 13 | 14 | constructor(private translateService: TranslateService) { 15 | this.languageKeys = [...this.languages.keys()]; 16 | } 17 | 18 | public getDefaultLang(){ 19 | let userLang = this.languageKeys[0]; 20 | const browserLangs = navigator.languages || [navigator.language]; 21 | for (const lang of browserLangs) { 22 | const baseLang = lang.split('-')[0]; 23 | if (this.languageKeys.includes(baseLang)) { 24 | userLang = baseLang; 25 | break; 26 | } 27 | } 28 | 29 | return userLang; 30 | } 31 | 32 | public getCurrentLang(){ 33 | const currentLang = localStorage.getItem('lang'); 34 | if(this.languageKeys.includes(currentLang)){ 35 | return currentLang; 36 | } 37 | return this.getDefaultLang(); 38 | } 39 | 40 | public setLang(lang: string){ 41 | localStorage.setItem('lang', lang); 42 | this.translateService.use(this.getCurrentLang()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2Enums.ts: -------------------------------------------------------------------------------- 1 | export enum Difficulty { 2 | Basic = 0, 3 | Advanced = 1, 4 | Expert = 2, 5 | Master = 3, 6 | ReMaster = 4, 7 | Strong = 5, 8 | } 9 | 10 | export enum ClearRank { 11 | D = 0, 12 | C = 1, 13 | B = 2, 14 | BB = 3, 15 | BBB = 4, 16 | A = 5, 17 | AA = 6, 18 | AAA = 7, 19 | S = 8, 20 | SP = 9, 21 | SS = 10, 22 | SSP = 11, 23 | SSS = 12, 24 | SSSP = 13, 25 | } 26 | 27 | export enum UdemaeName { 28 | 初心者 = 0, 29 | 見習い = 1, 30 | 駆け出し = 2, 31 | 修行中 = 3, 32 | 初段 = 4, 33 | 二段 = 5, 34 | 三段 = 6, 35 | 四段 = 7, 36 | 五段 = 8, 37 | 六段 = 9, 38 | 七段 = 10, 39 | 八段 = 11, 40 | 九段 = 12, 41 | 十段 = 13, 42 | 皆伝 = 14, 43 | 皆伝1 = 15, 44 | 皆伝2 = 16, 45 | 皆伝3 = 17, 46 | 皆伝4 = 18, 47 | 皆伝5 = 19, 48 | 皆伝6 = 20, 49 | 皆伝7 = 21, 50 | 皆伝8 = 22, 51 | 皆伝9 = 23, 52 | 皆伝10 = 24, 53 | } 54 | 55 | export enum ClassName { 56 | B5 = 0, 57 | B4 = 1, 58 | B3 = 2, 59 | B2 = 3, 60 | B1 = 4, 61 | A5 = 5, 62 | A4 = 6, 63 | A3 = 7, 64 | A2 = 8, 65 | A1 = 9, 66 | S5 = 10, 67 | S4 = 11, 68 | S3 = 12, 69 | S2 = 13, 70 | S1 = 14, 71 | SS5 = 15, 72 | SS4 = 16, 73 | SS3 = 17, 74 | SS2 = 18, 75 | SS1 = 19, 76 | SSS5 = 20, 77 | SSS4 = 21, 78 | SSS3 = 22, 79 | SSS2 = 23, 80 | SSS1 = 24, 81 | LEGEND = 25, 82 | } -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiEnums.ts: -------------------------------------------------------------------------------- 1 | export enum Difficulty { 2 | Basic = 0, 3 | Advanced = 1, 4 | Expert = 2, 5 | Master = 3, 6 | Lunatic = 10, // Client sends 10 as id of Lunatic difficulty to server 7 | } 8 | 9 | export enum PlayResult { 10 | Failed, 11 | Finish, 12 | Clear, 13 | Max 14 | } 15 | 16 | export enum NotesComboResult { 17 | None, 18 | FullCombo, 19 | AllBreak, 20 | Max, 21 | } 22 | 23 | export enum BellComboResult { 24 | None, 25 | FullBell, 26 | Max, 27 | } 28 | 29 | export enum RetireResult { 30 | None, 31 | NoLife, 32 | ScoreRetire, 33 | DeathSkill, 34 | Max, 35 | } 36 | 37 | export enum BattleRank { 38 | Invalid = -1, 39 | Begin = 0, 40 | None = 0, 41 | Fuka = 1, 42 | Ka = 2, 43 | Ryo = 3, 44 | Yu = 4, 45 | Shu = 5, 46 | Goku = 6, 47 | Goku1 = 7, 48 | Goku2 = 8, 49 | Goku3 = 9, 50 | Goku4 = 10, 51 | Goku5 = 11, 52 | End = 12, 53 | } 54 | 55 | export enum TechnicalRank { 56 | None = 0, 57 | D = 1, 58 | C = 2, 59 | B = 3, 60 | BB = 4, 61 | BBB = 5, 62 | A = 6, 63 | AA = 7, 64 | AAA = 8, 65 | S = 9, 66 | SS = 10, 67 | SSS = 11, 68 | SSS1 = 12, 69 | } 70 | 71 | // The AttributeType send by client is + 1. So the value here is start from 1 72 | export enum AttributeType { 73 | Fire = 1, 74 | Aqua = 2, 75 | Leaf = 3, 76 | Max = 4 77 | } 78 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-rating/ongeki-rating.component.css: -------------------------------------------------------------------------------- 1 | .rating-card{ 2 | min-width: 180px; 3 | } 4 | .jacket{ 5 | width: 5.6rem; 6 | aspect-ratio: 1; 7 | } 8 | 9 | .new-jacket{ 10 | width: 3.6rem; 11 | aspect-ratio: 1; 12 | border-top-left-radius: var(--bs-border-radius) !important; 13 | } 14 | @media (min-width:1400px){ 15 | .col-xxl-{ 16 | flex:0 0 auto;width:20% 17 | } 18 | } 19 | .difficulty { 20 | font-size: 0.7em; 21 | } 22 | 23 | .difficulty-basic { 24 | background: #2da060; 25 | border: 1px solid #145830; 26 | color: white; 27 | } 28 | 29 | .difficulty-advanced { 30 | background: #e6a047; 31 | border: 1px solid #995014; 32 | color: white; 33 | } 34 | 35 | .difficulty-expert { 36 | background: #e55353; 37 | border: 1px solid #7B1F18; 38 | color: white; 39 | } 40 | 41 | .difficulty-master { 42 | background: #9d5cb9; 43 | border: 1px solid #381C47; 44 | color: white; 45 | } 46 | 47 | .difficulty-lunatic { 48 | background: var(--bs-white); 49 | border: 1px solid var(--bs-danger); 50 | color: var(--bs-danger); 51 | } 52 | 53 | .honor-badge { 54 | aspect-ratio: 1; 55 | width: 28px; 56 | } 57 | 58 | .honor-star { 59 | aspect-ratio: 4.5; 60 | width: 3.6em; 61 | } 62 | 63 | .honor{ 64 | height: 28px; 65 | } 66 | 67 | @media (max-width:380px){ 68 | .row-cols-xxs-1>*{flex:0 0 auto;width:100%} 69 | } 70 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-song-list/ongeki-song-list.component.css: -------------------------------------------------------------------------------- 1 | .input-container:focus-within{ 2 | color: var(--bs-body-color); 3 | background-color: var(--bs-body-bg); 4 | border-color: #86b7fe; 5 | outline: 0; 6 | box-shadow: 0 0 0 .25rem rgba(13,110,253,.25); 7 | } 8 | 9 | table { 10 | width: 100%; 11 | } 12 | 13 | .song-info { 14 | padding: 4px; 15 | } 16 | 17 | .song-info .jacket-container { 18 | width: 5.6rem; 19 | min-width: 5.6rem; 20 | aspect-ratio: 1; 21 | } 22 | 23 | .song-info .song-info-id { 24 | font-size: 20px; 25 | } 26 | 27 | .song-info .song-info-title { 28 | font-size: 16px; 29 | } 30 | 31 | .song-info .song-info-artist { 32 | font-size: 12px; 33 | } 34 | 35 | .difficulty { 36 | font-size: 12px; 37 | } 38 | 39 | .difficulty-basic { 40 | background: #2da060; 41 | border: 1px solid #145830; 42 | color: white; 43 | } 44 | 45 | .difficulty-advanced { 46 | background: #e6a047; 47 | border: 1px solid #995014; 48 | color: white; 49 | } 50 | 51 | .difficulty-expert { 52 | background: #e55353; 53 | border: 1px solid #7B1F18; 54 | color: white; 55 | } 56 | 57 | .difficulty-master { 58 | background: #9d5cb9; 59 | border: 1px solid #381C47; 60 | color: white; 61 | } 62 | 63 | .difficulty-lunatic { 64 | background: var(--bs-white); 65 | border: 1px solid var(--bs-danger); 66 | color: var(--bs-danger); 67 | } 68 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/model/OngekiProfile.ts: -------------------------------------------------------------------------------- 1 | import {OngekiCard} from './OngekiCard'; 2 | import {OngekiCharacter} from './OngekiCharacter'; 3 | import {OngekiTrophy} from './OngekiTrophy'; 4 | 5 | export interface DisplayOngekiProfile { 6 | userName: string; 7 | level: number; 8 | reincarnationNum: number; 9 | lastPlayDate: string; 10 | lastDataVersion: string; 11 | lastRomVersion: string; 12 | exp: number; 13 | point: number; 14 | totalPoint: number; 15 | playCount: number; 16 | jewelCount: number; 17 | totalJewelCount: number; 18 | medalCount: number; 19 | playerRating: number; 20 | highestRating: number; 21 | newPlayerRating: number; 22 | newHighestRating: number; 23 | battlePoint: number; 24 | bestBattlePoint: number; 25 | rankId: number; 26 | rankPattern: number; 27 | nameplateId: number; 28 | trophyId: number; 29 | trophy: OngekiTrophy; 30 | cardId: number; 31 | characterId: number; 32 | sumTechHighScore: number; 33 | sumTechBasicHighScore: number; 34 | sumTechAdvancedHighScore: number; 35 | sumTechExpertHighScore: number; 36 | sumTechMasterHighScore: number; 37 | sumTechLunaticHighScore: number; 38 | sumBattleHighScore: number; 39 | sumBattleBasicHighScore: number; 40 | sumBattleAdvancedHighScore: number; 41 | sumBattleExpertHighScore: number; 42 | sumBattleMasterHighScore: number; 43 | sumBattleLunaticHighScore: number; 44 | } 45 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/chuni-music-db.service.ts: -------------------------------------------------------------------------------- 1 | import {Injectable} from '@angular/core'; 2 | import {ChusanMusic} from './model/ChusanMusic'; 3 | import {ApiService} from '../../../api.service'; 4 | import {Subject} from 'rxjs'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class ChusanMusicDbService { 10 | 11 | private dbSubject = new Subject>(); 12 | dbState = this.dbSubject.asObservable(); 13 | 14 | musicDb: Map; 15 | 16 | constructor(private api: ApiService) { 17 | let db = localStorage.getItem('chusanMusicDb'); 18 | if (db == null) { 19 | this.api.get('api/game/chuni/v2/data/music').subscribe( 20 | data => { 21 | db = data; 22 | localStorage.setItem('chusanMusicDb', JSON.stringify(db)); 23 | this.musicDb = this.parse(JSON.parse(db)); 24 | } 25 | ); 26 | } else { 27 | this.musicDb = this.parse(JSON.parse(db)); 28 | } 29 | } 30 | 31 | get(id: number): ChusanMusic { 32 | return this.musicDb.get(id); 33 | } 34 | 35 | getMusicDb(): Map { 36 | return this.musicDb; 37 | } 38 | 39 | private parse(db: ChusanMusic[]): Map { 40 | const result: Map = new Map(); 41 | db.forEach(x => { 42 | result.set(x.musicId, x); 43 | }); 44 | return result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-tech-honor-sprite.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import {TechnicalRank} from '../model/OngekiEnums'; 3 | 4 | @Pipe({ 5 | name: 'toTechHonorSprite' 6 | }) 7 | export class ToTechHonorSpritePipe implements PipeTransform { 8 | 9 | transform(value: number): string { 10 | switch (TechnicalRank[value]) { 11 | case 'D': 12 | return 'UI_SLC_MusicSelect_HornorBadge_D.webp'; 13 | case 'C': 14 | return 'UI_SLC_MusicSelect_HornorBadge_C.webp'; 15 | case 'B': 16 | return 'UI_SLC_MusicSelect_HornorBadge_B.webp'; 17 | case 'BB': 18 | return 'UI_SLC_MusicSelect_HornorBadge_BB.webp'; 19 | case 'BBB': 20 | return 'UI_SLC_MusicSelect_HornorBadge_BBB.webp'; 21 | case 'A': 22 | return 'UI_SLC_MusicSelect_HornorBadge_A.webp'; 23 | case 'AA': 24 | return 'UI_SLC_MusicSelect_HornorBadge_AA.webp'; 25 | case 'AAA': 26 | return 'UI_SLC_MusicSelect_HornorBadge_AAA.webp'; 27 | case 'S': 28 | return 'UI_SLC_MusicSelect_HornorBadge_S.webp'; 29 | case 'SS': 30 | return 'UI_SLC_MusicSelect_HornorBadge_SS.webp'; 31 | case 'SSS': 32 | return 'UI_SLC_MusicSelect_HornorBadge_SSS.webp'; 33 | case 'SSS1': 34 | return 'UI_SLC_MusicSelect_HornorBadge_SSSplus.webp'; 35 | } 36 | return null; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-name-setting/v2-name-setting.dialog.ts: -------------------------------------------------------------------------------- 1 | import {Component, Inject, Input} from '@angular/core'; 2 | import {NgbModal} from '@ng-bootstrap/ng-bootstrap'; 3 | import {V2SettingComponent} from '../v2-setting.component'; 4 | 5 | @Component({ 6 | selector: 'v2-name-setting-dialog', 7 | templateUrl: 'v2-name-setting.html', 8 | styleUrls: ['v2-name-setting.scss'], 9 | }) 10 | export class V2NameSettingDialog { 11 | 12 | parentComponent: any; 13 | @Input() public data: V2SettingComponent; 14 | userName: string; 15 | userNameBtnsSymbol = [ 16 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 17 | '.', '・', ':', ';', '?', '!', '~', '/', '+', '-', '×', '÷', '=', '♂', '♀', '∀', '#', '&', '*', '@', '☆', 18 | '○', '◎', '◇', '□', '△', '▽', '♪', '†', '‡', 'Σ', 'α', 'β', 'γ', 'θ', 'φ', 'ψ', 'ω', 'Д', 'ё' 19 | ]; 20 | constructor( 21 | public modalService: NgbModal, 22 | ) { 23 | } 24 | 25 | ngOnInit(): void { 26 | this.userName = this.data.userName as unknown as string; 27 | } 28 | 29 | 30 | insertCharacter(item: string) { 31 | if (item) { 32 | const oldUserName = this.userName; 33 | this.userName = oldUserName + item; 34 | console.log(this.userName); 35 | } 36 | } 37 | 38 | } 39 | 40 | export interface V2NameSettingData { 41 | userName: string; 42 | } 43 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/model/Maimai2Profile.ts: -------------------------------------------------------------------------------- 1 | export interface DisplayMaimai2Profile { 2 | userName: string; 3 | iconId: number; 4 | plateId: number; 5 | titleId: number; 6 | partnerId: number; 7 | frameId: number; 8 | selectMapId: number; 9 | totalAwake: number; 10 | gradeRating: number; 11 | musicRating: number; 12 | playerRating: number; 13 | highestRating: number; 14 | gradeRank: number; 15 | classRank: number; 16 | courseRank: number; 17 | charaSlot: string; 18 | charaLockSlot: string; 19 | playCount: number; 20 | eventWatchedDate: string; 21 | lastRomVersion: string; 22 | lastDataVersion: string; 23 | lastPlayDate: string; 24 | playVsCount: number; 25 | playSyncCount: number; 26 | winCount: number; 27 | helpCount: number; 28 | comboCount: number; 29 | totalDeluxscore: number; 30 | totalBasicDeluxscore: number; 31 | totalAdvancedDeluxscore: number; 32 | totalExpertDeluxscore: number; 33 | totalMasterDeluxscore: number; 34 | totalReMasterDeluxscore: number; 35 | totalSync: number; 36 | totalBasicSync: number; 37 | totalAdvancedSync: number; 38 | totalExpertSync: number; 39 | totalMasterSync: number; 40 | totalReMasterSync: number; 41 | totalAchievement: number; 42 | totalBasicAchievement: number; 43 | totalAdvancedAchievement: number; 44 | totalExpertAchievement: number; 45 | totalMasterAchievement: number; 46 | totalReMasterAchievement: number; 47 | } 48 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-setting/v2-version-setting/v2-version-setting.html: -------------------------------------------------------------------------------- 1 | 32 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-dxpass/maimai2-dxpass.component.css: -------------------------------------------------------------------------------- 1 | .freedom-pass { 2 | border: 1px solid #3d91cd; 3 | color: transparent; 4 | background: #e625bf linear-gradient(to right, #6db1f6, #11c1ea); 5 | -webkit-background-clip: text; 6 | background-clip: text; 7 | } 8 | 9 | 10 | .gold-pass { 11 | border: 1px solid #995014; 12 | color: transparent; 13 | background: #d1aa79 linear-gradient(45deg, #f4b400, #d1aa79, #b77a3b); 14 | -webkit-background-clip: text; 15 | background-clip: text; 16 | } 17 | 18 | 19 | .normal-pass { 20 | background: #451d0c; 21 | border: 1px solid #374908; 22 | color: white; 23 | } 24 | 25 | .silver-pass { 26 | background: #09343c; 27 | border: 1px solid #3a4165; 28 | color: #6394d5; 29 | } 30 | 31 | .expired-pass { 32 | background: #686363; 33 | border: 1px solid #c6b1b1; 34 | color: white; 35 | } 36 | 37 | /*.pass-text {*/ 38 | /* display: flex;*/ 39 | /* align-items: center;*/ 40 | /* b {*/ 41 | /* padding: 0 3px;*/ 42 | /* }*/ 43 | /*}*/ 44 | 45 | .card { 46 | position: relative; /* 使子元素可以绝对定位 */ 47 | } 48 | 49 | .overlay-image { 50 | position: absolute; /* 用绝对定位确保图像重叠 */ 51 | top: 0; /* 根据需求设置偏移 */ 52 | left: 0; /* 根据需求设置偏移 */ 53 | width: 100%; /* 确保图像填满父容器 */ 54 | height: auto; /* 高度自适应 */ 55 | opacity: 1; /* 如果需要,可以调整此值以实现透明效果 */ 56 | z-index: 1; /* 设置图层顺序 */ 57 | } 58 | 59 | /* 框架图像可能需要更高的 z-index */ 60 | .frame-image { 61 | z-index: 2; /* 若要确保框架在最上层 */ 62 | } 63 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/util/to-tech-rating.pipe.ts: -------------------------------------------------------------------------------- 1 | import {Pipe, PipeTransform} from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toTechRating' 5 | }) 6 | export class ToTechRatingPipe implements PipeTransform { 7 | 8 | // type: 1 for 13.00 + 2.00, 2 for 15.00 9 | transform(diff: string, score: number): string { 10 | if (diff === null) { return null; } 11 | const diffNum = parseFloat(diff); 12 | let result: number; 13 | const scoreZero = 500000; 14 | const rateTbls = [ 15 | [800000, -600], 16 | [900000, -400], 17 | [970000, 0], 18 | [990000, 100], 19 | [1000000, 150], 20 | [1007500, 200], 21 | [1100000, 200] 22 | ]; 23 | const level100 = Math.floor(diffNum * 100.0 + 0.5); 24 | let num = 0; 25 | 26 | if (score <= rateTbls[0][0]){ 27 | num = (level100 + rateTbls[0][1]) * (score - scoreZero) / (rateTbls[0][0] - scoreZero); 28 | } else { 29 | for (let i = 1; i < 7; i++){ 30 | const rateTbl = rateTbls[i]; 31 | if (score <= rateTbl[0]){ 32 | const rateTbl2 = rateTbls[i - 1]; 33 | num = level100 + rateTbl2[1]; 34 | num += (rateTbl[1] - rateTbl2[1]) * (score - rateTbl2[0]) / (rateTbl[0] - rateTbl2[0]); 35 | break; 36 | } 37 | } 38 | } 39 | 40 | num = Math.floor(num); 41 | result = Math.max(num, 0) / 100.0; 42 | 43 | if (result === 0) { 44 | return '0.00'; 45 | } else { 46 | return result.toFixed(2).toString(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/api.service.ts: -------------------------------------------------------------------------------- 1 | import {HttpClient, HttpParams} from '@angular/common/http'; 2 | import {Injectable} from '@angular/core'; 3 | import {BehaviorSubject} from 'rxjs'; 4 | import {environment} from '../environments/environment'; 5 | 6 | @Injectable({ 7 | providedIn: 'root' 8 | }) 9 | export class ApiService { 10 | 11 | private loadingSubject = new BehaviorSubject(false); 12 | loadingState = this.loadingSubject.asObservable(); 13 | 14 | constructor(private http: HttpClient) { 15 | } 16 | 17 | get(path: string, params?: HttpParams) { 18 | return this.http.get(this.getHost() + path, {params}); 19 | } 20 | 21 | post(path: string, data?: object, params?: HttpParams) { 22 | return this.http.post(this.getHost() + path, data, {params}); 23 | } 24 | 25 | put(path: string, data?: object, params?: HttpParams) { 26 | return this.http.put(this.getHost() + path, data, {params}); 27 | } 28 | 29 | delete(path: string, params?: HttpParams, body?) { 30 | return this.http.delete(this.getHost() + path, {params, body}); 31 | } 32 | 33 | getHost(): string { 34 | return environment.apiServer; 35 | } 36 | 37 | show() { 38 | Promise.resolve().then(() => this.loadingSubject.next(true)); 39 | } 40 | 41 | hide() { 42 | Promise.resolve().then(() => this.loadingSubject.next(false)); 43 | } 44 | 45 | } 46 | 47 | export class Resp { 48 | status: string; 49 | data: object; 50 | } 51 | 52 | export interface LoadingState { 53 | show: boolean; 54 | } 55 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/to-tech-rating.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | 3 | @Pipe({ 4 | name: 'toTechRating' 5 | }) 6 | export class ToTechRatingPipe implements PipeTransform { 7 | 8 | transform(score: number, chartConstant: number): number { 9 | const C = chartConstant; 10 | const S = score; 11 | 12 | let result; 13 | 14 | if (S >= 1009000) { 15 | result = C + 215; 16 | } else if (S >= 1007500) { 17 | result = Math.floor(((S - 1007500) * 15) / 1500 + (C + 200)); 18 | } else if (S >= 1005000) { 19 | result = Math.floor(((S - 1005000) * 50) / 2500 + (C + 150)); 20 | } else if (S >= 1000000) { 21 | result = Math.floor(((S - 1000000) * 50) / 5000 + (C + 100)); 22 | } else if (S >= 975000) { 23 | result = Math.floor(((S - 975000) * 100) / 25000 + C); 24 | } else if (S >= 925000) { 25 | result = Math.floor(((S - 925000) * 300) / 50000 + (C - 300)); 26 | } else if (S >= 900000) { 27 | result = Math.floor(((S - 900000) * 200) / 25000 + (C - 500)); 28 | } else if (S >= 800000) { 29 | const deltaR = Math.floor((C - 500) / 2); 30 | result = Math.floor(((S - 800000) * deltaR) / 100000 + deltaR); 31 | } else if (S >= 500000) { 32 | const deltaR = Math.floor((C - 500) / 2); 33 | result = Math.floor(((S - 500000) * deltaR) / 300000); 34 | } else { 35 | result = 0; 36 | } 37 | 38 | if (result < 0){ 39 | result = 0; 40 | } 41 | 42 | return result; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/util/release-tag.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable({ 4 | providedIn: 'root' 5 | }) 6 | export class ReleaseTagService { 7 | 8 | releaseTags = [ 9 | 'v1 1.00.00', 'v1 1.05.00', 10 | 'v1 1.10.00', 'v1 1.15.00', 11 | 'v1 1.20.00', 'v1 1.25.00', 12 | 'v1 1.30.00', 'v1 1.35.00', 13 | 'v1 1.40.00', 'v1 1.45.00', 14 | 'v1 1.50.00', 'v1 1.55.00', 15 | 'v2 2.00.00', 'v2 2.05.00', 16 | 'v2 2.10.00', 'v2 2.15.00', 17 | 'v2 2.20.00', 'v2 2.25.00', 18 | 'v2 2.30.00' 19 | ]; 20 | releaseTagMap = new Map([ 21 | ['v1 1.00.00', 'ORIGIN'], 22 | ['v1 1.05.00', 'ORIGIN PLUS'], 23 | ['v1 1.10.00', 'AIR'], 24 | ['v1 1.15.00', 'AIR PLUS'], 25 | ['v1 1.20.00', 'STAR'], 26 | ['v1 1.25.00', 'STAR PLUS'], 27 | ['v1 1.30.00', 'AMAZON'], 28 | ['v1 1.35.00', 'AMAZON PLUS'], 29 | ['v1 1.40.00', 'CRYSTAL'], 30 | ['v1 1.45.00', 'CRYSTAL PLUS'], 31 | ['v1 1.50.00', 'PARADISE'], 32 | ['v1 1.55.00', 'PARADISE LOST'], 33 | ['v2 2.00.00', 'NEW'], 34 | ['v2 2.05.00', 'NEW PLUS'], 35 | ['v2 2.10.00', 'SUN'], 36 | ['v2 2.15.00', 'SUN PLUS'], 37 | ['v2 2.20.00', 'LUMINOUS'], 38 | ['v2 2.25.00', 'LUMINOUS PLUS'], 39 | ['v2 2.30.00', 'VERSE'], 40 | ]); 41 | 42 | constructor() { } 43 | 44 | public getReleaseTags(): string[] { 45 | return this.releaseTags; 46 | } 47 | 48 | public getName(releaseTag: string): string { 49 | return this.releaseTagMap.get(releaseTag); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/model/V2Profile.ts: -------------------------------------------------------------------------------- 1 | export interface V2Profile { 2 | userName: string; 3 | level: number; 4 | reincarnationNum: number; 5 | exp: number; 6 | point: number; 7 | totalPoint: bigint; 8 | playCount: number; 9 | multiPlayCount: number; 10 | multiWinCount: number; 11 | requestResCount: number; 12 | acceptResCount: number; 13 | successResCount: number; 14 | playerRating: number; 15 | highestRating: number; 16 | nameplateId: number; 17 | frameId: number; 18 | characterId: number; 19 | trophyId: number; 20 | trophyIdSub1: number; 21 | trophyIdSub2: number; 22 | playedTutorialBit: number; 23 | firstTutorialCancelNum: number; 24 | masterTutorialCancelNum: number; 25 | totalRepertoireCount: number; 26 | totalMapNum: number; 27 | totalHiScore: bigint; 28 | totalBasicHighScore: bigint; 29 | totalAdvancedHighScore: bigint; 30 | totalExpertHighScore: bigint; 31 | totalMasterHighScore: bigint; 32 | totalUltimaHighScore: bigint; 33 | friendCount: number; 34 | firstGameId: string; 35 | firstRomVersion: string; 36 | lastRomVersion: string; 37 | firstDataVersion: string; 38 | lastDataVersion: string; 39 | firstPlayDate: Date; 40 | lastPlayDate: Date; 41 | courseClass: number; 42 | overPowerPoint: number; 43 | overPowerRate: number; 44 | mapIconId: number; 45 | voiceId: number; 46 | avatarWear: number; 47 | avatarHead: number; 48 | avatarFace: number; 49 | avatarSkin: number; 50 | avatarItem: number; 51 | avatarFront: number; 52 | avatarBack: number; 53 | } 54 | -------------------------------------------------------------------------------- /src/app/home/home.component.css: -------------------------------------------------------------------------------- 1 | .cannot-drag { 2 | -webkit-user-drag: none; 3 | } 4 | 5 | .logo-container { 6 | position: relative; 7 | display: flex; 8 | justify-content: center; 9 | cursor: pointer; 10 | overflow: hidden; 11 | } 12 | 13 | .logo { 14 | position: absolute; 15 | z-index: 99; 16 | max-height: 100%; 17 | max-width: 100%; 18 | top: 0; 19 | transform: translate(-50%, 0); 20 | left: 50%; 21 | height: 100%; 22 | } 23 | 24 | .logo-bg { 25 | background: url('src/assets/turtle.svg') no-repeat center center / 100%; 26 | } 27 | 28 | .logo-bottom { 29 | z-index: 10 !important; 30 | } 31 | 32 | .logo-img_fault { 33 | background-blend-mode: screen; 34 | } 35 | 36 | .logo-container .logo-box { 37 | position: relative; 38 | width: 200px; 39 | height: 200px; 40 | } 41 | 42 | .logo-container .ongekiHead { 43 | width: 92%; 44 | position: absolute; 45 | /*top: 4.5%;*/ 46 | top: 3.5%; 47 | left: -24%; 48 | z-index: 99; 49 | } 50 | 51 | .logo-img_fault::after,.logo-img_fault::before { 52 | content: ""; 53 | position: absolute; 54 | width: 100%; 55 | height: 100%; 56 | top: 0; 57 | left: 0; 58 | mask: url('src/assets/turtle.svg') center/contain; 59 | } 60 | 61 | .logo-img_fault::after { 62 | transform: translateX(-2%); 63 | background-color: #f00; 64 | } 65 | 66 | .logo-img_fault::before{ 67 | transform: translateX(2%); 68 | background-color: #00f; 69 | } 70 | 71 | .game-item{ 72 | display: flex; 73 | justify-content: space-between; 74 | align-items: center; 75 | font-weight: bold; 76 | } 77 | -------------------------------------------------------------------------------- /src/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RinNet", 3 | "short_name": "RinNet", 4 | "theme_color": "#bdcf47", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "scope": "./", 8 | "start_url": "./", 9 | "icons": [ 10 | { 11 | "src": "assets/icons/turtle-72x72.png", 12 | "sizes": "72x72", 13 | "type": "image/png", 14 | "purpose": "maskable any" 15 | }, 16 | { 17 | "src": "assets/icons/turtle-96x96.png", 18 | "sizes": "96x96", 19 | "type": "image/png", 20 | "purpose": "maskable any" 21 | }, 22 | { 23 | "src": "assets/icons/turtle-128x128.png", 24 | "sizes": "128x128", 25 | "type": "image/png", 26 | "purpose": "maskable any" 27 | }, 28 | { 29 | "src": "assets/icons/turtle-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image/png", 32 | "purpose": "maskable any" 33 | }, 34 | { 35 | "src": "assets/icons/turtle-152x152.png", 36 | "sizes": "152x152", 37 | "type": "image/png", 38 | "purpose": "maskable any" 39 | }, 40 | { 41 | "src": "assets/icons/turtle-192x192.png", 42 | "sizes": "192x192", 43 | "type": "image/png", 44 | "purpose": "maskable any" 45 | }, 46 | { 47 | "src": "assets/icons/turtle-384x384.png", 48 | "sizes": "384x384", 49 | "type": "image/png", 50 | "purpose": "maskable any" 51 | }, 52 | { 53 | "src": "assets/icons/turtle-512x512.png", 54 | "sizes": "512x512", 55 | "type": "image/png", 56 | "purpose": "maskable any" 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-music-ranking/ongeki-music-ranking.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import {OngekiGameRanking} from '../model/OngekiGameRanking'; 3 | import {ApiService} from '../../../api.service'; 4 | import {environment} from '../../../../environments/environment'; 5 | import {OngekiMusic} from '../model/OngekiMusic'; 6 | import {OngekiSongScoreRankingComponent} from '../ongeki-song-score-ranking/ongeki-song-score-ranking.component'; 7 | import {NgbOffcanvas} from '@ng-bootstrap/ng-bootstrap'; 8 | 9 | @Component({ 10 | selector: 'app-ongeki-music-ranking', 11 | templateUrl: './ongeki-music-ranking.component.html', 12 | styleUrls: ['./ongeki-music-ranking.component.scss'] 13 | }) 14 | export class OngekiMusicRankingComponent implements OnInit { 15 | ongekiGameRankings: OngekiGameRanking[] = []; 16 | host = environment.assetsHost; 17 | 18 | displayedColumns: string[] = ['ranking', 'music.name', 'playCount', 'state']; 19 | 20 | constructor( 21 | private api: ApiService, 22 | private offcanvasService: NgbOffcanvas) { } 23 | 24 | ngOnInit(): void { 25 | this.getData(); 26 | } 27 | 28 | private getData() { 29 | this.api.get('api/game/ongeki/data/musicRanking') 30 | .subscribe(data => { 31 | this.ongekiGameRankings = data; 32 | }); 33 | } 34 | 35 | showDetail(music: OngekiMusic) { 36 | const offcanvasRef = this.offcanvasService.open(OngekiSongScoreRankingComponent, { 37 | position: 'end', 38 | scroll: false, 39 | // panelClass: 'ongeki-song-score-ranking', 40 | }); 41 | offcanvasRef.componentInstance.music = music; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/app/sega/maimai2/maimai2-profile/maimai2-profile.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {ApiService} from '../../../api.service'; 3 | import {AuthenticationService} from '../../../auth/authentication.service'; 4 | import {MessageService} from '../../../message.service'; 5 | import {HttpParams} from '@angular/common/http'; 6 | import {DisplayMaimai2Profile} from '../model/Maimai2Profile'; 7 | import {NgxIndexedDBService} from 'ngx-indexed-db'; 8 | import {UdemaeName, ClassName} from '../model/Maimai2Enums'; 9 | import { UserService } from 'src/app/user.service'; 10 | 11 | @Component({ 12 | selector: 'app-maimai2-profile', 13 | templateUrl: './maimai2-profile.component.html', 14 | styleUrls: ['./maimai2-profile.component.css'] 15 | }) 16 | export class Maimai2ProfileComponent implements OnInit { 17 | 18 | profile: DisplayMaimai2Profile; 19 | udemaeRank = UdemaeName; 20 | classRank = ClassName; 21 | 22 | constructor( 23 | private api: ApiService, 24 | private userService: UserService, 25 | private messageService: MessageService, 26 | private dbService: NgxIndexedDBService 27 | ) { 28 | } 29 | 30 | ngOnInit() { 31 | const aimeId = String(this.userService.currentUser.defaultCard.extId); 32 | const param = new HttpParams().set('aimeId', aimeId); 33 | this.api.get('api/game/maimai2/profile', param).subscribe( 34 | data => { 35 | this.profile = data; 36 | }, 37 | error => this.messageService.notice(error) 38 | ); 39 | } 40 | getFormattedNumberByDigit(input: number, digit: number): string { 41 | return input.toString().padStart(digit, '0'); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2-character/v2-character.component.scss: -------------------------------------------------------------------------------- 1 | .character-card { 2 | user-select: none; 3 | 4 | .character-img { 5 | width: 100%; 6 | aspect-ratio: 1; 7 | } 8 | 9 | .character-title { 10 | font-size: small; 11 | text-align: center; 12 | } 13 | 14 | .character-message { 15 | width: 80%; 16 | padding: 1rem 0; 17 | display: flex; 18 | justify-content: space-between; 19 | 20 | &>span { 21 | background: var(--bs-tertiary-color); 22 | border: 1px solid #381C47; 23 | color: white; 24 | &:nth-child(2) { 25 | background: var(--bs-primary-border-subtle); 26 | } 27 | } 28 | } 29 | } 30 | 31 | .image-switch{ 32 | user-select: none; 33 | position: absolute; 34 | bottom: 1em; 35 | right: 1em; 36 | } 37 | 38 | .marquee { 39 | overflow: hidden; 40 | text-overflow: fade; 41 | text-wrap: nowrap; 42 | } 43 | 44 | .marquee .marquee-wrap { 45 | width: 100%; 46 | transform: translateX(0); 47 | } 48 | 49 | .marquee .marquee-content { 50 | transform: translateX(0); 51 | } 52 | 53 | .character-card:hover .marquee .marquee-wrap { 54 | animation: marquee-wrap 4s infinite linear; 55 | } 56 | 57 | .marquee .marquee-content { 58 | float: left; 59 | white-space: nowrap; 60 | min-width: 100%; 61 | } 62 | 63 | .character-card:hover .marquee .marquee-content { 64 | animation: marquee-content 4s infinite linear; 65 | } 66 | 67 | @keyframes marquee-wrap { 68 | 0%, 69 | 30% { 70 | transform: translateX(0); 71 | } 72 | 70%, 73 | 100% { 74 | transform: translateX(100%); 75 | } 76 | } 77 | 78 | @keyframes marquee-content { 79 | 0%, 80 | 30% { 81 | transform: translateX(0); 82 | } 83 | 70%, 84 | 100% { 85 | transform: translateX(-100%); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /ssl/naominet.live.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJrfvmlspmxaoO 3 | 2SXPt55b5tM+4j1HBglMLDW8O490eMLhyI/Oy3RIl+aslk4bIovSw5uuUJ2lFxUn 4 | bX2H98T9GAtaI3BubkjYaG1/F0mq+IMJ+d8mnZv4WwiggFOGJfPs8qH7/AUpwKFw 5 | lZgbSjQv/wT4zaPz0v6QJxYzFS0THB4x9nSOjEyrdTHCOpPXAcEhxzLM++0Emwsq 6 | 8pkOxDQSXXbM02CCf4nhTCVlkOSIgcyUVHmPZ364S+tPZg911PK2AkSIM9Ph+D5s 7 | rbPwxkhyXXkRMKE7Br3FKSXvvhNz9WPDsgd3VzF9XOoqg8fjElfsZ/aLP+fLZ+gk 8 | uyb0Ql6pAgMBAAECggEAF35BLwAHRVgGwpKIjU0YMR/vIS7lEPoyyJEI1GvCvwBX 9 | QUpl+CKqoc8yE44xvIb2bz+SiciByKqq7+wY+KcD5zCvF9mzfeWybiUiBjE+B2DK 10 | EPYuyLaI5fIiy+GO+TxAESzFck9OAapbE/yVGq627BVirKH11JAST9QBycMQfF5v 11 | 9Loz1dDscvbHDekKwTy8dL35QQEpbaTi6wSZ7WkWT+007ntNmnj1On3y8JO3XYoU 12 | BwhMtkf9SZ2m43kmKVS0fLivOO2Q13Ek/vbGBs9HStRscsxntvrS+qfky3xKhbS+ 13 | 8ELX/gDjRrGUHQB5TPx9hs3OgGJj8uxgcSJ0wV93gQKBgQDkXB730YBsw7i5dqSo 14 | qo9OU1k/zJh3HS58UgnI/k+Apvizkp6ywXuQRaLU3ZzzLTWmrwFCRrjnBkMn2Xag 15 | UXH+PWHXbjM+SC1Krq05lbPzxY5QXYx9QgKXGCLmE5V0hvtyo/Z3bCYOUxcrLA2I 16 | A05zbkE6dWlh5JGeua3g6DbP6QKBgQDiFyitWjlcnDQmHbnTuYEatRBmgcmDLD+h 17 | RMBOffUqw2iw1AF81A1IODz61h0BiUGmYexNls6ucbHULl20BRAPEuPQFEAFGz1G 18 | 4kRqk10KAGiJ1M1LJtAPDW+yJzg4yLOIyRcof6gJTMy02x14CPNquWjtWxQ86Aqt 19 | qjtLCE6gwQKBgBqO9DMSNINxx9waBlBvdbdATlLzMpA33p4q1GSB3zExOh94X+ie 20 | RAalcqibFZPaoDDAjb7threnrMvHqNpAXqeY7/YkJOWLc2kKI69cz878HO8P0jUH 21 | JlH4RqbHhExHHptYomOFOm/UDg/BUdmNuOQH4KIx4Y23DZCOO8C6gRVxAoGBALwR 22 | DZodqgd6O/rU0UXoUhdYNBtArNI7VXadjOX96pk20Pf+cnpWnfHMLhVtU9V6SizP 23 | 2dO0tZnwIz9fjjx31aLkULI+lf5paTB0ePq6ODNgoZS9ekOgNoO+5oGoFCFP+d+3 24 | flcG0U1jIAj1F29I6sqFDl4aXBxJ3NAXAZlpgJZBAoGASRoganqD8kl+hECKa+CT 25 | nVTEifU4E/gGLJH+haMVxuMxaPWM3sB8jbMZead0cmQYwnVMsFLHOsY0TX/Oe6OO 26 | +BiynwxlL8v0e1zR0VSAa7S7Dp8AHZx/av+r/uRb+vnGcirWu/EifmITdwaQ+H4Y 27 | ttfW6VZcYvq4aXjU5M8bD6c= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /src/app/not-found/not-found.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, ElementRef, QueryList, Renderer2, ViewChildren} from '@angular/core'; 2 | import {environment} from '../../environments/environment'; 3 | 4 | @Component({ 5 | selector: 'app-not-found', 6 | templateUrl: './not-found.component.html', 7 | styleUrls: ['./not-found.component.css'] 8 | }) 9 | export class NotFoundComponent { 10 | @ViewChildren('faultTurtle') faultTurtle: QueryList; 11 | faultTimer = null; 12 | host = environment.assetsHost; 13 | constructor( 14 | private renderer: Renderer2, 15 | ) { 16 | } 17 | 18 | 19 | // ngOnInit(): void { 20 | // clearInterval(this.faultTimer); 21 | // this.faultTimer = setInterval(() => { 22 | // this.faultTurtle.forEach((img) => { 23 | // this.renderer.setStyle(img.nativeElement, 'transform', `translate(${Math.random() * 60 - 30}%, ${Math.random() * 60 - 30}%)`); 24 | // this.renderer.addClass(img.nativeElement, 'logo-img_fault'); 25 | // const x = Math.random() * 100; 26 | // const y = Math.random() * 100; 27 | // const h = Math.random() * 50 + 50; 28 | // const w = Math.random() * 40 + 10; 29 | // this.renderer.setStyle(img.nativeElement, 'clipPath', ` 30 | // polygon(${x}% ${y}%, ${x + w}% ${y}%, ${x + w}% ${y + h}%, ${x}% ${y + h}%)`); 31 | // }); 32 | // }, 30); 33 | // setTimeout(() => this.faultStop(), 3000); 34 | // } 35 | // 36 | // faultStop(): void { 37 | // clearInterval(this.faultTimer); 38 | // this.faultTurtle.forEach((img) => { 39 | // this.renderer.removeClass(img.nativeElement, 'logo-img_fault'); 40 | // this.renderer.setStyle(img.nativeElement, 'transform', ''); 41 | // this.renderer.setStyle(img.nativeElement, 'clipPath', ''); 42 | // }); 43 | // } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /src/app/sega/chunithm/v2/v2.routing.ts: -------------------------------------------------------------------------------- 1 | import {RouterModule, Routes} from '@angular/router'; 2 | import {V2ProfileComponent} from './v2-profile/v2-profile.component'; 3 | import {V2RatingComponent} from './v2-rating/v2-rating.component'; 4 | import {V2RecentComponent} from './v2-recent/v2-recent.component'; 5 | import {V2SettingComponent} from './v2-setting/v2-setting.component'; 6 | import {V2SonglistComponent} from './v2-songlist/v2-songlist.component'; 7 | import {V2CharacterComponent} from './v2-character/v2-character.component'; 8 | import {V2UserBoxComponent} from './v2-userbox/v2-userbox.component'; 9 | import {V2UserRankingComponent} from './v2-user-ranking/v2-user-ranking.component'; 10 | import {V2SongScoreRankingComponent} from './v2-song-score-ranking/v2-song-score-ranking.component'; 11 | import {V2RivalListComponent} from './v2-rival-list/v2-rival-list.component'; 12 | 13 | const routes: Routes = [ 14 | {path: 'profile', component: V2ProfileComponent, data: {title: 'Profile'}}, 15 | {path: 'rating', component: V2RatingComponent, data: {title: 'Rating'}}, 16 | {path: 'recent', component: V2RecentComponent, data: {title: 'Recent'}}, 17 | {path: 'song', component: V2SonglistComponent, data: {title: 'MusicList'}}, 18 | {path: 'character', component: V2CharacterComponent, data: {title: 'Character'}}, 19 | {path: 'rival', component: V2RivalListComponent, data: {title: 'Rival'}}, 20 | {path: 'userRanking', component: V2UserRankingComponent, data: {title: 'UserRanking'}}, 21 | {path: 'setting', component: V2SettingComponent, data: {title: 'Settings'}}, 22 | {path: 'userbox', component: V2UserBoxComponent, data: {title: 'Userbox'}}, 23 | {path: 'song/ranking/:id/:level', component: V2SongScoreRankingComponent, data: {title: 'ScoreRanking'}}, 24 | ]; 25 | 26 | export const V2Routes = RouterModule.forChild(routes); 27 | -------------------------------------------------------------------------------- /src/assets/gitlab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/app/sega/ongeki/ongeki-recent-item/ongeki-recent-item.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, OnInit} from '@angular/core'; 2 | import {PlayerPlaylog} from '../model/PlayerPlaylog'; 3 | import {AttributeType, BattleRank, Difficulty, TechnicalRank} from '../model/OngekiEnums'; 4 | import {environment} from '../../../../environments/environment'; 5 | import {NgbModal, NgbOffcanvas} from '@ng-bootstrap/ng-bootstrap'; 6 | import {Router} from '@angular/router'; 7 | import {OngekiMusic} from '../model/OngekiMusic'; 8 | import {OngekiSongScoreRankingComponent} from '../ongeki-song-score-ranking/ongeki-song-score-ranking.component'; 9 | 10 | @Component({ 11 | selector: 'app-ongeki-recent-item', 12 | templateUrl: './ongeki-recent-item.component.html', 13 | styleUrls: ['./ongeki-recent-item.component.css'], 14 | inputs: ['playLog'] 15 | }) 16 | export class OngekiRecentItemComponent implements OnInit { 17 | playLog: PlayerPlaylog; 18 | host = environment.assetsHost; 19 | difficulty = Difficulty; 20 | battleRank = BattleRank; 21 | technicalRank = TechnicalRank; 22 | attributeType = AttributeType; 23 | isCollapsed = false; 24 | protected readonly Difficulty = Difficulty; 25 | protected readonly Math = Math; 26 | 27 | constructor( 28 | private modalService: NgbModal, 29 | public router: Router, 30 | private offcanvasService: NgbOffcanvas, 31 | ) { } 32 | 33 | ngOnInit(): void { 34 | } 35 | open(content) { 36 | this.modalService.open(content, { centered: true }); 37 | } 38 | 39 | showDetail(music: OngekiMusic) { 40 | const offcanvasRef = this.offcanvasService.open(OngekiSongScoreRankingComponent, { 41 | position: 'end', 42 | scroll: false, 43 | }); 44 | offcanvasRef.componentInstance.music = music; 45 | } 46 | 47 | getArrayFromNumber(n: number): any[] { 48 | return new Array(n); 49 | } 50 | } 51 | --------------------------------------------------------------------------------