├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
└── workflows
│ ├── alpha.yml
│ ├── alpha_build_manually_without_sign.yml
│ ├── auto_close_issues.yml
│ ├── close_inactive_issues.yml
│ ├── features.yml
│ └── release.yml
├── .gitignore
├── .gitmodules
├── .idea
├── .gitignore
├── kotlinc.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
├── schemas
│ └── dev.aaa1115910.bv.dao.AppDatabase
│ │ ├── 1.json
│ │ ├── 2.json
│ │ └── 3.json
└── src
│ ├── debug
│ ├── AndroidManifest.xml
│ └── res
│ │ └── values
│ │ └── strings.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-playstore.png
│ ├── kotlin
│ │ ├── coil
│ │ │ └── transform
│ │ │ │ └── BlurTransformation.kt
│ │ ├── de
│ │ │ └── schnettler
│ │ │ │ └── datastore
│ │ │ │ └── manager
│ │ │ │ ├── DataStoreManager.kt
│ │ │ │ └── PreferenceRequest.kt
│ │ └── dev
│ │ │ └── aaa1115910
│ │ │ └── bv
│ │ │ ├── BVApp.kt
│ │ │ ├── activities
│ │ │ ├── MainActivity.kt
│ │ │ ├── pgc
│ │ │ │ ├── PgcIndexActivity.kt
│ │ │ │ └── anime
│ │ │ │ │ └── AnimeTimelineActivity.kt
│ │ │ ├── search
│ │ │ │ ├── SearchInputActivity.kt
│ │ │ │ └── SearchResultActivity.kt
│ │ │ ├── settings
│ │ │ │ ├── LogsActivity.kt
│ │ │ │ ├── MediaCodecActivity.kt
│ │ │ │ ├── SettingsActivity.kt
│ │ │ │ └── SpeedTestActivity.kt
│ │ │ ├── user
│ │ │ │ ├── FavoriteActivity.kt
│ │ │ │ ├── FollowActivity.kt
│ │ │ │ ├── FollowingSeasonActivity.kt
│ │ │ │ ├── HistoryActivity.kt
│ │ │ │ ├── LoginActivity.kt
│ │ │ │ ├── ToViewActivity.kt
│ │ │ │ ├── UserInfoActivity.kt
│ │ │ │ ├── UserLockSettingsActivity.kt
│ │ │ │ └── UserSwitchActivity.kt
│ │ │ └── video
│ │ │ │ ├── RemoteControllerPanelDemoActivity.kt
│ │ │ │ ├── SeasonInfoActivity.kt
│ │ │ │ ├── TagActivity.kt
│ │ │ │ ├── UpInfoActivity.kt
│ │ │ │ ├── VideoInfoActivity.kt
│ │ │ │ ├── VideoPlayerActivity.kt
│ │ │ │ └── VideoPlayerV3Activity.kt
│ │ │ ├── component
│ │ │ ├── BottomTip.kt
│ │ │ ├── BvPlayerPreview.kt
│ │ │ ├── Carousel.kt
│ │ │ ├── DanmakuPlayerCompose.kt
│ │ │ ├── DevelopingTip.kt
│ │ │ ├── FocusGroup.kt
│ │ │ ├── FpsMonitor.kt
│ │ │ ├── LibVLCDownloaderDialog.kt
│ │ │ ├── LoadingTip.kt
│ │ │ ├── RemoteControlPanelDemo.kt
│ │ │ ├── TopNav.kt
│ │ │ ├── UpIcon.kt
│ │ │ ├── UserPanel.kt
│ │ │ ├── buttons
│ │ │ │ ├── FavoriteButton.kt
│ │ │ │ └── SeasonInfoButtons.kt
│ │ │ ├── controllers
│ │ │ │ ├── BottomControls.kt
│ │ │ │ ├── BottomSubtitle.kt
│ │ │ │ ├── BufferingTip.kt
│ │ │ │ ├── GoBackHistoryTip.kt
│ │ │ │ ├── PauseIcon.kt
│ │ │ │ ├── TopController.kt
│ │ │ │ ├── VideoListController.kt
│ │ │ │ ├── VideoPlayerController.kt
│ │ │ │ ├── VideoPlayerMenuController.kt
│ │ │ │ └── info
│ │ │ │ │ └── VideoPlayerInfoTip.kt
│ │ │ ├── controllers2
│ │ │ │ ├── BottomSubtitle.kt
│ │ │ │ ├── ControllerVideoInfo.kt
│ │ │ │ ├── MenuController.kt
│ │ │ │ ├── PlayStateTips.kt
│ │ │ │ ├── ProgressSeekThumb.kt
│ │ │ │ ├── SeekController.kt
│ │ │ │ ├── SkipTip.kt
│ │ │ │ ├── VideoListController.kt
│ │ │ │ ├── VideoPlayerController.kt
│ │ │ │ ├── VideoProgressSeek.kt
│ │ │ │ ├── VideoShot.kt
│ │ │ │ └── playermenu
│ │ │ │ │ ├── ClosedCaptionMenu.kt
│ │ │ │ │ ├── DanmakuMenu.kt
│ │ │ │ │ ├── MenuNav.kt
│ │ │ │ │ ├── PictureMenu.kt
│ │ │ │ │ └── component
│ │ │ │ │ ├── CheckBoxMenuList.kt
│ │ │ │ │ ├── MenuListItem.kt
│ │ │ │ │ ├── RadioMenuList.kt
│ │ │ │ │ └── StepLessMenuItem.kt
│ │ │ ├── createCustomInitialFocusRestorerModifiers.kt
│ │ │ ├── ifElse.kt
│ │ │ ├── pgc
│ │ │ │ └── IndexFilter.kt
│ │ │ ├── search
│ │ │ │ ├── SearchKeyword.kt
│ │ │ │ └── SoftKeyboard.kt
│ │ │ ├── settings
│ │ │ │ ├── CookiesDialog.kt
│ │ │ │ ├── SettingListItem.kt
│ │ │ │ ├── SettingSwitchListItem.kt
│ │ │ │ ├── SettingsMenuSelectItem.kt
│ │ │ │ └── UpdateDialog.kt
│ │ │ └── videocard
│ │ │ │ ├── LargeVideoCard.kt
│ │ │ │ ├── SeasonCard.kt
│ │ │ │ ├── SmallVideoCard.kt
│ │ │ │ └── VideosRow.kt
│ │ │ ├── dao
│ │ │ ├── AppDatabase.kt
│ │ │ ├── SearchHistoryDao.kt
│ │ │ └── UserDao.kt
│ │ │ ├── entity
│ │ │ ├── Audio.kt
│ │ │ ├── AuthData.kt
│ │ │ ├── DanmakuSize.kt
│ │ │ ├── DanmakuTransparency.kt
│ │ │ ├── PlayerType.kt
│ │ │ ├── Resolution.kt
│ │ │ ├── VideoAspectRatio.kt
│ │ │ ├── VideoCodec.kt
│ │ │ ├── carddata
│ │ │ │ ├── SeasonCardData.kt
│ │ │ │ └── VideoCardData.kt
│ │ │ ├── db
│ │ │ │ ├── SearchHistoryDB.kt
│ │ │ │ └── UserDB.kt
│ │ │ └── proxy
│ │ │ │ └── ProxyArea.kt
│ │ │ ├── network
│ │ │ ├── GithubApi.kt
│ │ │ ├── HttpServer.kt
│ │ │ ├── VlcLibsApi.kt
│ │ │ └── entity
│ │ │ │ └── GithubRelease.kt
│ │ │ ├── repository
│ │ │ ├── UserRepository.kt
│ │ │ └── VideoInfoRepository.kt
│ │ │ ├── screen
│ │ │ ├── MainScreen.kt
│ │ │ ├── RegionBlockScreen.kt
│ │ │ ├── SeasonInfoScreen.kt
│ │ │ ├── TagScreen.kt
│ │ │ ├── VideoInfoScreen.kt
│ │ │ ├── VideoPlayerScreen.kt
│ │ │ ├── VideoPlayerV3Screen.kt
│ │ │ ├── login
│ │ │ │ ├── AppQRLoginContent.kt
│ │ │ │ ├── LoginScreen.kt
│ │ │ │ └── SmsLoginContent.kt
│ │ │ ├── main
│ │ │ │ ├── DrawerContent.kt
│ │ │ │ ├── HomeContent.kt
│ │ │ │ ├── PgcContent.kt
│ │ │ │ ├── UgcContent.kt
│ │ │ │ ├── home
│ │ │ │ │ ├── DynamicsScreen.kt
│ │ │ │ │ ├── PopularScreen.kt
│ │ │ │ │ └── RecommendScreen.kt
│ │ │ │ ├── pgc
│ │ │ │ │ ├── AnimeContent.kt
│ │ │ │ │ ├── DocumentaryContent.kt
│ │ │ │ │ ├── GuoChuangContent.kt
│ │ │ │ │ ├── MovieContent.kt
│ │ │ │ │ ├── PgcCommon.kt
│ │ │ │ │ ├── PgcIndexScreen.kt
│ │ │ │ │ ├── TvContent.kt
│ │ │ │ │ ├── VarietyContent.kt
│ │ │ │ │ └── anime
│ │ │ │ │ │ └── AnimeTimelineScreen.kt
│ │ │ │ └── ugc
│ │ │ │ │ ├── AnimalContent.kt
│ │ │ │ │ ├── CarContent.kt
│ │ │ │ │ ├── CinephileContent.kt
│ │ │ │ │ ├── DanceContent.kt
│ │ │ │ │ ├── DougaContent.kt
│ │ │ │ │ ├── EntContent.kt
│ │ │ │ │ ├── FashionContent.kt
│ │ │ │ │ ├── FoodContent.kt
│ │ │ │ │ ├── GameContent.kt
│ │ │ │ │ ├── InformationContent.kt
│ │ │ │ │ ├── KichikuContent.kt
│ │ │ │ │ ├── KnowledgeContent.kt
│ │ │ │ │ ├── LifeContent.kt
│ │ │ │ │ ├── MuiscContent.kt
│ │ │ │ │ ├── SportsContent.kt
│ │ │ │ │ ├── TechContent.kt
│ │ │ │ │ ├── UgcChildRegionButtons.kt
│ │ │ │ │ └── UgcCommon.kt
│ │ │ ├── search
│ │ │ │ ├── SearchInputScreen.kt
│ │ │ │ ├── SearchResultFilter.kt
│ │ │ │ └── SearchResultScreen.kt
│ │ │ ├── settings
│ │ │ │ ├── LogsScreen.kt
│ │ │ │ ├── MediaCodecScreen.kt
│ │ │ │ ├── SettingsScreen.kt
│ │ │ │ ├── SpeedTestScreen.kt
│ │ │ │ └── content
│ │ │ │ │ ├── AboutSetting.kt
│ │ │ │ │ ├── ApiSetting.kt
│ │ │ │ │ ├── AudioSetting.kt
│ │ │ │ │ ├── InfoSetting.kt
│ │ │ │ │ ├── NetworkSetting.kt
│ │ │ │ │ ├── OtherSetting.kt
│ │ │ │ │ ├── PlayerTypeSetting.kt
│ │ │ │ │ ├── ResolutionSetting.kt
│ │ │ │ │ ├── StorageSetting.kt
│ │ │ │ │ ├── UISetting.kt
│ │ │ │ │ └── VideoCodecSetting.kt
│ │ │ └── user
│ │ │ │ ├── FavoriteScreen.kt
│ │ │ │ ├── FollowScreen.kt
│ │ │ │ ├── FollowingSeasonFilter.kt
│ │ │ │ ├── FollowingSeasonScreen.kt
│ │ │ │ ├── HistoryScreen.kt
│ │ │ │ ├── ToViewScreen.kt
│ │ │ │ ├── UpInfoScreen.kt
│ │ │ │ ├── UserInfoScreen.kt
│ │ │ │ ├── UserSwitchScreen.kt
│ │ │ │ └── lock
│ │ │ │ ├── UnlockSwitchUserContent.kt
│ │ │ │ ├── UnlockUserScreen.kt
│ │ │ │ └── UserLockSettingsScreen.kt
│ │ │ ├── ui
│ │ │ └── theme
│ │ │ │ ├── Theme.kt
│ │ │ │ └── Typography.kt
│ │ │ ├── util
│ │ │ ├── AbiUtil.kt
│ │ │ ├── CodecUtil.kt
│ │ │ ├── EnumExtends.kt
│ │ │ ├── Extends.kt
│ │ │ ├── FirebaseUtil.kt
│ │ │ ├── ImageExtends.kt
│ │ │ ├── KLoggerExtends.kt
│ │ │ ├── LogCatcherUtil.kt
│ │ │ ├── ModifierExtends.kt
│ │ │ ├── NetworkUtil.kt
│ │ │ ├── PartitionUtil.kt
│ │ │ ├── PgcIndexParamExtends.kt
│ │ │ ├── PgcTypeExtends.kt
│ │ │ ├── PlayerActivityUtil.kt
│ │ │ ├── Prefs.kt
│ │ │ ├── Timer.kt
│ │ │ ├── UgcTypeExtends.kt
│ │ │ └── VideoShotExtends.kt
│ │ │ └── viewmodel
│ │ │ ├── PlayerVIewModel.kt
│ │ │ ├── TagViewModel.kt
│ │ │ ├── UserViewModel.kt
│ │ │ ├── VideoPlayerV3ViewModel.kt
│ │ │ ├── home
│ │ │ ├── DynamicViewModel.kt
│ │ │ ├── PopularViewModel.kt
│ │ │ └── RecommendViewModel.kt
│ │ │ ├── index
│ │ │ └── PgcIndexViewModel.kt
│ │ │ ├── login
│ │ │ ├── AppQrLoginViewModel.kt
│ │ │ └── SmsLoginViewModel.kt
│ │ │ ├── pgc
│ │ │ ├── PgcAnimeViewModel.kt
│ │ │ ├── PgcDocumentaryViewModel.kt
│ │ │ ├── PgcGuoChuangViewModel.kt
│ │ │ ├── PgcMovieViewModel.kt
│ │ │ ├── PgcTvViewModel.kt
│ │ │ ├── PgcVarietyViewModel.kt
│ │ │ └── PgcViewModel.kt
│ │ │ ├── search
│ │ │ ├── SearchInputViewModel.kt
│ │ │ └── SearchResultViewModel.kt
│ │ │ ├── user
│ │ │ ├── FavoriteViewModel.kt
│ │ │ ├── FollowViewModel.kt
│ │ │ ├── FollowingSeasonViewModel.kt
│ │ │ ├── HistoryViewModel.kt
│ │ │ ├── ToViewViewModel.kt
│ │ │ └── UpInfoViewModel.kt
│ │ │ └── video
│ │ │ └── VideoDetailViewModel.kt
│ └── res
│ │ ├── drawable
│ │ ├── ic_banner.webp
│ │ ├── ic_banner_foreground.xml
│ │ ├── ic_danmaku_count.xml
│ │ ├── ic_gamer_ani.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_play_count.xml
│ │ └── ic_up.xml
│ │ ├── font
│ │ └── noto_sans_math_regular.ttf
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_banner.xml
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── network_security_config.xml
│ │ └── provider_paths.xml
│ ├── r8Test
│ ├── AndroidManifest.xml
│ └── res
│ │ └── values
│ │ └── strings.xml
│ └── test
│ └── kotlin
│ ├── android
│ └── util
│ │ └── Log.kt
│ └── dev
│ └── aaa1115910
│ └── bv
│ └── network
│ └── GithubApiTest.kt
├── bili-api-grpc
├── .gitignore
├── build.gradle.kts
└── proto
│ ├── bilibili
│ ├── account
│ │ └── fission
│ │ │ └── v1
│ │ │ └── fission.proto
│ ├── ad
│ │ └── v1
│ │ │ └── ad.proto
│ ├── api
│ │ ├── player
│ │ │ └── v1
│ │ │ │ └── player.proto
│ │ ├── probe
│ │ │ └── v1
│ │ │ │ └── probe.proto
│ │ └── ticket
│ │ │ └── v1
│ │ │ └── ticket.proto
│ ├── app
│ │ ├── archive
│ │ │ ├── middleware
│ │ │ │ └── v1
│ │ │ │ │ └── preload.proto
│ │ │ └── v1
│ │ │ │ └── archive.proto
│ │ ├── card
│ │ │ └── v1
│ │ │ │ ├── ad.proto
│ │ │ │ ├── card.proto
│ │ │ │ ├── common.proto
│ │ │ │ ├── double.proto
│ │ │ │ └── single.proto
│ │ ├── click
│ │ │ └── v1
│ │ │ │ └── heartbeat.proto
│ │ ├── distribution
│ │ │ ├── setting
│ │ │ │ ├── download.proto
│ │ │ │ ├── dynamic.proto
│ │ │ │ ├── experimental.proto
│ │ │ │ ├── internaldevice.proto
│ │ │ │ ├── night.proto
│ │ │ │ ├── other.proto
│ │ │ │ ├── pegasus.proto
│ │ │ │ ├── play.proto
│ │ │ │ ├── privacy.proto
│ │ │ │ └── search.proto
│ │ │ └── v1
│ │ │ │ └── distribution.proto
│ │ ├── dynamic
│ │ │ ├── common
│ │ │ │ └── dynamic.proto
│ │ │ ├── v1
│ │ │ │ └── dynamic.proto
│ │ │ └── v2
│ │ │ │ ├── campus.proto
│ │ │ │ ├── dynamic.proto
│ │ │ │ └── opus.proto
│ │ ├── interfaces
│ │ │ └── v1
│ │ │ │ ├── history.proto
│ │ │ │ ├── media.proto
│ │ │ │ ├── search.proto
│ │ │ │ └── space.proto
│ │ ├── listener
│ │ │ └── v1
│ │ │ │ └── listener.proto
│ │ ├── playeronline
│ │ │ └── v1
│ │ │ │ └── playeronline.proto
│ │ ├── playerunite
│ │ │ ├── pgcanymodel
│ │ │ │ └── PGCAnyModel.proto
│ │ │ ├── ugcanymodel
│ │ │ │ └── UGCAnyModel.proto
│ │ │ └── v1
│ │ │ │ └── playerunite.proto
│ │ ├── playurl
│ │ │ └── v1
│ │ │ │ └── playurl.proto
│ │ ├── resource
│ │ │ ├── privacy
│ │ │ │ └── v1
│ │ │ │ │ └── api.proto
│ │ │ └── v1
│ │ │ │ └── module.proto
│ │ ├── search
│ │ │ └── v2
│ │ │ │ └── search.proto
│ │ ├── show
│ │ │ ├── gateway
│ │ │ │ └── v1
│ │ │ │ │ └── service.proto
│ │ │ ├── mixture
│ │ │ │ └── v1
│ │ │ │ │ └── mixture.proto
│ │ │ ├── popular
│ │ │ │ └── v1
│ │ │ │ │ └── popular.proto
│ │ │ ├── rank
│ │ │ │ └── v1
│ │ │ │ │ └── rank.proto
│ │ │ └── region
│ │ │ │ └── v1
│ │ │ │ └── region.proto
│ │ ├── space
│ │ │ └── v1
│ │ │ │ └── space.proto
│ │ ├── splash
│ │ │ └── v1
│ │ │ │ └── splash.proto
│ │ ├── topic
│ │ │ └── v1
│ │ │ │ └── topic.proto
│ │ ├── view
│ │ │ └── v1
│ │ │ │ └── view.proto
│ │ ├── viewunite
│ │ │ ├── common.proto
│ │ │ ├── pgcanymodel.proto
│ │ │ ├── ugcanymodel.proto
│ │ │ └── v1
│ │ │ │ └── viewunite.proto
│ │ └── wall
│ │ │ └── v1
│ │ │ └── wall.proto
│ ├── broadcast
│ │ ├── message
│ │ │ ├── editor
│ │ │ │ └── notify.proto
│ │ │ ├── esports
│ │ │ │ └── notify.proto
│ │ │ ├── fission
│ │ │ │ └── notify.proto
│ │ │ ├── im
│ │ │ │ └── notify.proto
│ │ │ ├── main
│ │ │ │ ├── dm.proto
│ │ │ │ ├── native.proto
│ │ │ │ ├── resource.proto
│ │ │ │ └── search.proto
│ │ │ ├── note
│ │ │ │ └── sync.proto
│ │ │ ├── ogv
│ │ │ │ ├── freya.proto
│ │ │ │ └── live.proto
│ │ │ ├── ticket
│ │ │ │ └── activitygame.proto
│ │ │ └── tv
│ │ │ │ └── proj.proto
│ │ ├── v1
│ │ │ ├── broadcast.proto
│ │ │ ├── laser.proto
│ │ │ ├── mod.proto
│ │ │ ├── push.proto
│ │ │ ├── room.proto
│ │ │ └── test.proto
│ │ └── v2
│ │ │ └── laser.proto
│ ├── cheese
│ │ └── gateway
│ │ │ └── player
│ │ │ └── v1
│ │ │ └── playurl.proto
│ ├── community
│ │ └── service
│ │ │ ├── dm
│ │ │ └── v1
│ │ │ │ └── dm.proto
│ │ │ └── govern
│ │ │ └── v1
│ │ │ └── govern.proto
│ ├── dagw
│ │ └── component
│ │ │ └── avatar
│ │ │ ├── common
│ │ │ └── common.proto
│ │ │ └── v1
│ │ │ ├── avatar.proto
│ │ │ └── plugin.proto
│ ├── dynamic
│ │ ├── common
│ │ │ └── dynamic.proto
│ │ ├── gw
│ │ │ └── gateway.proto
│ │ └── interfaces
│ │ │ └── feed
│ │ │ └── v1
│ │ │ └── api.proto
│ ├── gaia
│ │ └── gw
│ │ │ └── gw_api.proto
│ ├── im
│ │ ├── interfaces
│ │ │ ├── inner-interface
│ │ │ │ └── v1
│ │ │ │ │ └── api.proto
│ │ │ └── v1
│ │ │ │ └── im.proto
│ │ └── type
│ │ │ └── im.proto
│ ├── live
│ │ ├── app
│ │ │ └── room
│ │ │ │ └── v1
│ │ │ │ └── room.proto
│ │ └── general
│ │ │ └── interfaces
│ │ │ └── v1
│ │ │ └── interfaces.proto
│ ├── main
│ │ ├── common
│ │ │ └── arch
│ │ │ │ └── doll
│ │ │ │ └── v1
│ │ │ │ └── doll.proto
│ │ └── community
│ │ │ └── reply
│ │ │ └── v1
│ │ │ └── reply.proto
│ ├── metadata
│ │ ├── device
│ │ │ └── device.proto
│ │ ├── fawkes
│ │ │ └── fawkes.proto
│ │ ├── locale
│ │ │ └── locale.proto
│ │ ├── metadata.proto
│ │ ├── network
│ │ │ └── network.proto
│ │ ├── parabox
│ │ │ └── parabox.proto
│ │ └── restriction
│ │ │ └── restriction.proto
│ ├── pagination
│ │ └── pagination.proto
│ ├── pangu
│ │ └── gallery
│ │ │ └── v1
│ │ │ └── gallery.proto
│ ├── pgc
│ │ ├── gateway
│ │ │ └── player
│ │ │ │ ├── v1
│ │ │ │ └── playurl.proto
│ │ │ │ └── v2
│ │ │ │ └── playurl.proto
│ │ └── service
│ │ │ └── premiere
│ │ │ └── v1
│ │ │ └── premiere.proto
│ ├── playershared
│ │ └── playershared.proto
│ ├── polymer
│ │ ├── app
│ │ │ └── search
│ │ │ │ └── v1
│ │ │ │ └── search.proto
│ │ ├── community
│ │ │ └── govern
│ │ │ │ └── v1
│ │ │ │ └── govern.proto
│ │ ├── contract
│ │ │ └── v1
│ │ │ │ └── contract.proto
│ │ ├── demo
│ │ │ └── demo.proto
│ │ └── list
│ │ │ └── v1
│ │ │ └── list.proto
│ ├── relation
│ │ └── interfaces
│ │ │ └── api.proto
│ ├── render
│ │ └── render.proto
│ ├── rpc
│ │ └── status.proto
│ ├── tv
│ │ └── interfaces
│ │ │ └── dm
│ │ │ └── v1
│ │ │ └── dm.proto
│ ├── vega
│ │ └── deneb
│ │ │ └── v1
│ │ │ └── deneb.proto
│ └── web
│ │ ├── interfaces
│ │ └── v1
│ │ │ └── interfaces.proto
│ │ └── space
│ │ └── v1
│ │ └── space.proto
│ ├── common
│ └── ErrorProto.proto
│ ├── datacenter
│ └── hakase
│ │ └── protobuf
│ │ └── android_device_info.proto
│ └── pgc
│ ├── biz
│ └── room.proto
│ └── gateway
│ └── vega
│ └── v1
│ └── vega.proto
├── bili-api
├── .gitignore
├── build.gradle.kts
├── example-response
│ └── live-event
│ │ ├── COMBO_SEND.json5
│ │ ├── DANMU_MSG.json5
│ │ ├── ENTRY_EFFECT.json5
│ │ ├── GUARD_BUY.json5
│ │ ├── HOT_RANK_CHANGED.json5
│ │ ├── HOT_RANK_CHANGED_V2.json5
│ │ ├── HOT_RANK_SETTLEMENT.json5
│ │ ├── HOT_RANK_SETTLEMENT_V2.json5
│ │ ├── HOT_ROOM_NOTIFY.json5
│ │ ├── INTERACT_WORD.json5
│ │ ├── LIKE_INFO_V3_CLICK.json5
│ │ ├── LIKE_INFO_V3_UPDATE.json5
│ │ ├── LIVE_INTERACTIVE_GAME.json5
│ │ ├── LIVE_MULTI_VIEW_CHANGE.json5
│ │ ├── NOTICE_MSG.json5
│ │ ├── ONLINE_RANK_COUNT.json5
│ │ ├── ONLINE_RANK_TOP3.json5
│ │ ├── ONLINE_RANK_V2.json5
│ │ ├── PREPARING.json5
│ │ ├── ROOM_REAL_TIME_MESSAGE_UPDATE.json
│ │ ├── SEND_GIFT.json
│ │ ├── STOP_LIVE_ROOM_LIST.json5
│ │ ├── SUPER_CHAT_ENTRANCE.json5
│ │ ├── SUPER_CHAT_MESSAGE.json5
│ │ ├── SUPER_CHAT_MESSAGE_JPN.json5
│ │ ├── USER_TOAST_MSG.json5
│ │ ├── WATCHED_CHANGE.json5
│ │ └── WIDGET_BANNER.json5
└── src
│ ├── main
│ └── kotlin
│ │ ├── com
│ │ └── tfowl
│ │ │ └── ktor
│ │ │ └── client
│ │ │ └── plugins
│ │ │ └── JsoupPlugin.kt
│ │ └── dev
│ │ └── aaa1115910
│ │ └── biliapi
│ │ ├── entity
│ │ ├── ApiType.kt
│ │ ├── CarouselData.kt
│ │ ├── CodeType.kt
│ │ ├── Favorite.kt
│ │ ├── PlayData.kt
│ │ ├── danmaku
│ │ │ └── DanmakuMask.kt
│ │ ├── home
│ │ │ └── RecommendData.kt
│ │ ├── login
│ │ │ ├── Captcha.kt
│ │ │ ├── QR.kt
│ │ │ └── Sms.kt
│ │ ├── pgc
│ │ │ ├── PgcFeedData.kt
│ │ │ ├── PgcItem.kt
│ │ │ ├── PgcType.kt
│ │ │ └── index
│ │ │ │ ├── IndexParams.kt
│ │ │ │ └── PgcIndexData.kt
│ │ ├── rank
│ │ │ └── Popular.kt
│ │ ├── search
│ │ │ └── Hotword.kt
│ │ ├── season
│ │ │ ├── FollowingSeasons.kt
│ │ │ ├── IndexResult.kt
│ │ │ └── Timeline.kt
│ │ ├── ugc
│ │ │ ├── UgcItem.kt
│ │ │ ├── UgcType.kt
│ │ │ └── region
│ │ │ │ ├── UgcRegionData.kt
│ │ │ │ ├── UgcRegionListData.kt
│ │ │ │ └── UgcRegionPage.kt
│ │ ├── user
│ │ │ ├── Author.kt
│ │ │ ├── Dynamic.kt
│ │ │ ├── FollowedUser.kt
│ │ │ ├── History.kt
│ │ │ ├── Space.kt
│ │ │ └── ToView.kt
│ │ └── video
│ │ │ ├── Dimension.kt
│ │ │ ├── Heartbeat.kt
│ │ │ ├── RelatedVideo.kt
│ │ │ ├── Subtitle.kt
│ │ │ ├── Tag.kt
│ │ │ ├── VideoDetail.kt
│ │ │ ├── VideoPage.kt
│ │ │ ├── VideoShot.kt
│ │ │ └── season
│ │ │ ├── Episode.kt
│ │ │ ├── PgcSeason.kt
│ │ │ ├── SeasonDetail.kt
│ │ │ └── Section.kt
│ │ ├── grpc
│ │ └── utils
│ │ │ ├── Channel.kt
│ │ │ └── StatusExtends.kt
│ │ ├── http
│ │ ├── BiliHttpApi.kt
│ │ ├── BiliHttpProxyApi.kt
│ │ ├── BiliLiveHttpApi.kt
│ │ ├── BiliPassportHttpApi.kt
│ │ ├── BiliPlusHttpApi.kt
│ │ ├── entity
│ │ │ ├── BiliResponse.kt
│ │ │ ├── biliplus
│ │ │ │ └── View.kt
│ │ │ ├── danmaku
│ │ │ │ └── DanmakuResponse.kt
│ │ │ ├── dynamic
│ │ │ │ └── DynamicResponse.kt
│ │ │ ├── history
│ │ │ │ └── HistoryData.kt
│ │ │ ├── home
│ │ │ │ ├── RcmdIndexData.kt
│ │ │ │ └── RcmdTopData.kt
│ │ │ ├── index
│ │ │ │ ├── IndexFilter.kt
│ │ │ │ ├── IndexFilterArea.kt
│ │ │ │ ├── IndexFilterProducerId.kt
│ │ │ │ ├── IndexFilterStyle.kt
│ │ │ │ ├── IndexOrder.kt
│ │ │ │ └── IndexResult.kt
│ │ │ ├── live
│ │ │ │ ├── HistoryDanmaku.kt
│ │ │ │ ├── LiveDanmuInfoResponse.kt
│ │ │ │ ├── LiveEvent.kt
│ │ │ │ ├── LiveFrame.kt
│ │ │ │ └── LiveRoomPlayInfoResponse.kt
│ │ │ ├── login
│ │ │ │ ├── Captcha.kt
│ │ │ │ ├── qr
│ │ │ │ │ ├── AppQR.kt
│ │ │ │ │ └── WebQR.kt
│ │ │ │ └── sms
│ │ │ │ │ ├── SendSmsResponse.kt
│ │ │ │ │ └── SmsLoginResponse.kt
│ │ │ ├── pgc
│ │ │ │ ├── PgcFeed.kt
│ │ │ │ ├── PgcFeedV3.kt
│ │ │ │ └── PgcWebInitialStateData.kt
│ │ │ ├── proxy
│ │ │ │ └── PlayUrl.kt
│ │ │ ├── region
│ │ │ │ ├── RegionDynamic.kt
│ │ │ │ ├── RegionDynamicList.kt
│ │ │ │ └── RegionLocs.kt
│ │ │ ├── search
│ │ │ │ ├── KeywordSuggest.kt
│ │ │ │ ├── SearchCost.kt
│ │ │ │ ├── SearchResult.kt
│ │ │ │ ├── SearchResultItem.kt
│ │ │ │ └── SearchSquare.kt
│ │ │ ├── season
│ │ │ │ ├── AppSeasonData.kt
│ │ │ │ ├── Episode.kt
│ │ │ │ ├── Follow.kt
│ │ │ │ ├── SeasonSection.kt
│ │ │ │ ├── WebFollowingSeason.kt
│ │ │ │ └── WebSeasonData.kt
│ │ │ ├── subtitle
│ │ │ │ └── Subtitle.kt
│ │ │ ├── toview
│ │ │ │ └── ToViewData.kt
│ │ │ ├── user
│ │ │ │ ├── Follow.kt
│ │ │ │ ├── LevelInfo.kt
│ │ │ │ ├── Nameplate.kt
│ │ │ │ ├── Official.kt
│ │ │ │ ├── Pendant.kt
│ │ │ │ ├── Profession.kt
│ │ │ │ ├── Relation.kt
│ │ │ │ ├── SpaceVideoData.kt
│ │ │ │ ├── Staff.kt
│ │ │ │ ├── UserCardInfoResponse.kt
│ │ │ │ ├── UserGarb.kt
│ │ │ │ ├── UserHonours.kt
│ │ │ │ ├── UserInfoResponse.kt
│ │ │ │ ├── UserSelfInfoResponse.kt
│ │ │ │ ├── Vip.kt
│ │ │ │ ├── favorite
│ │ │ │ │ ├── CntInfo.kt
│ │ │ │ │ ├── FavoriteFolderInfo.kt
│ │ │ │ │ ├── FavoriteFolderInfoListData.kt
│ │ │ │ │ ├── FavoriteItem.kt
│ │ │ │ │ ├── Upper.kt
│ │ │ │ │ └── UserFavoriteFoldersData.kt
│ │ │ │ └── garb
│ │ │ │ │ ├── CardBg.kt
│ │ │ │ │ ├── Equip.kt
│ │ │ │ │ └── Item.kt
│ │ │ ├── video
│ │ │ │ ├── AddCoin.kt
│ │ │ │ ├── PlayUrlResponse.kt
│ │ │ │ ├── PopularVideosResponse.kt
│ │ │ │ ├── RelatedVideosResponse.kt
│ │ │ │ ├── SetVideoFavorite.kt
│ │ │ │ ├── Tag.kt
│ │ │ │ ├── Timeline.kt
│ │ │ │ ├── UgcSeason.kt
│ │ │ │ ├── VideoDetail.kt
│ │ │ │ ├── VideoInfo.kt
│ │ │ │ ├── VideoMoreInfo.kt
│ │ │ │ └── VideoShot.kt
│ │ │ └── web
│ │ │ │ ├── Hover.kt
│ │ │ │ └── Nav.kt
│ │ └── util
│ │ │ ├── ApiSign.kt
│ │ │ ├── BiliAppConf.kt
│ │ │ ├── Buvid.kt
│ │ │ ├── CommonEnumIntSerializer.kt
│ │ │ └── Zlib.kt
│ │ ├── repositories
│ │ ├── AuthRepository.kt
│ │ ├── ChannelRepository.kt
│ │ ├── FavoriteRepository.kt
│ │ ├── HistoryRepository.kt
│ │ ├── LoginRepository.kt
│ │ ├── PgcRepository.kt
│ │ ├── RecommendVideoRepository.kt
│ │ ├── SearchRepository.kt
│ │ ├── SeasonRepository.kt
│ │ ├── ToViewRepository.kt
│ │ ├── UgcRepository.kt
│ │ ├── UserRepository.kt
│ │ ├── VideoDetailRepository.kt
│ │ └── VideoPlayRepository.kt
│ │ ├── util
│ │ ├── AvBvConverter.kt
│ │ ├── Extends.kt
│ │ └── UrlUtil.kt
│ │ └── websocket
│ │ └── LiveDataWebSocket.kt
│ └── test
│ ├── kotlin
│ └── dev
│ │ └── aaa1115910
│ │ └── biliapi
│ │ ├── BvLoginRepositoryTest.kt
│ │ ├── entity
│ │ └── DanmakuMaskTest.kt
│ │ ├── http
│ │ ├── BiliHttpApiTest.kt
│ │ ├── BiliLiveHttpApiTest.kt
│ │ ├── BiliPassportHttpApiTest.kt
│ │ └── BiliPlusHttpApiTest.kt
│ │ ├── repositories
│ │ ├── FavoriteRepositoryTest.kt
│ │ ├── HistoryRepositoryTest.kt
│ │ ├── PgcRepositoryTest.kt
│ │ ├── RecommendVideoRepositoryTest.kt
│ │ ├── SearchRepositoryTest.kt
│ │ ├── SeasonRepositoryTest.kt
│ │ ├── UgcRepositoryTest.kt
│ │ ├── UserRepositoryTest.kt
│ │ ├── VideoDetailRepositoryTest.kt
│ │ └── VideoPlayRepositoryTest.kt
│ │ └── websocket
│ │ └── LiveDataWebSocketTest.kt
│ └── resources
│ ├── 3540266_25_2.exp.mobmask
│ └── 3540266_25_2.exp.webmask
├── bili-subtitle
├── .gitignore
├── build.gradle.kts
└── src
│ ├── main
│ └── kotlin
│ │ └── dev
│ │ └── aaa1115910
│ │ └── bilisubtitle
│ │ ├── SubtitleEncoder.kt
│ │ ├── SubtitleParser.kt
│ │ └── entity
│ │ ├── BiliSubtitle.kt
│ │ ├── SrtSubtitle.kt
│ │ ├── SubtitleItem.kt
│ │ └── Timestamp.kt
│ └── test
│ ├── kotlin
│ └── dev
│ │ └── aaa1115910
│ │ └── bilisubtitle
│ │ ├── SubtitleEncoderTest.kt
│ │ ├── SubtitleParserTest.kt
│ │ └── entity
│ │ └── TimestampTest.kt
│ └── resources
│ ├── example.bcc
│ └── example.srt
├── build.gradle.kts
├── buildSrc
├── .gitignore
├── build.gradle.kts
└── src
│ └── main
│ └── kotlin
│ ├── AppConfiguration.kt
│ └── ProtobufConfiguration.kt
├── bv-player
├── .gitignore
├── build.gradle.kts
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── dev
│ │ └── aaa1115910
│ │ └── bv
│ │ └── player
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── GlobalSign ECC Root CA R5.crt
│ └── kotlin
│ │ └── dev
│ │ └── aaa1115910
│ │ └── bv
│ │ └── player
│ │ ├── AbstractVideoPlayer.kt
│ │ ├── BvVideoPlayer.kt
│ │ ├── Extends.kt
│ │ ├── OkHttpUtil.kt
│ │ ├── VideoPlayerListener.kt
│ │ ├── VideoPlayerOptions.kt
│ │ ├── factory
│ │ └── PlayerFactory.kt
│ │ └── impl
│ │ └── exo
│ │ ├── ExoMediaPlayer.kt
│ │ └── ExoPlayerFactory.kt
│ └── test
│ └── java
│ └── dev
│ └── aaa1115910
│ └── bv
│ └── player
│ └── ExampleUnitTest.kt
├── gradle.properties
├── gradle
├── androidx.versions.toml
├── gradle.versions.toml
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: 功能需求
2 | description: 为项目提供建议
3 | title: "以简单的一段字概括你的建议"
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | ## 反馈须知
9 | - 请务必完整填写下面的内容,如果缺少必要的信息,将无法解决任何问题
10 | - 一个 issue 请只反馈一个 bug 或功能建议,一次性反馈多个不同的问题或建议或将会被直接关闭
11 | - 注意你的标题,以简单的一段字概括你所遇到的问题。不要使用无意义内容或全部复制粘贴
12 | - 提出建议也不一定会做,这不可能是万能的许愿机,如果自己确实想要,建议 fork 项目自己实现
13 | - 该项目不为任何旧版本提供维护支持,请务必确认已更新到最新版本
14 |
15 | - type: textarea
16 | id: problem-description
17 | validations:
18 | required: true
19 | attributes:
20 | label: 问题描述
21 | description: 描述你想要解决的问题或者功能的使用场景
22 | placeholder: 请描述你遇到的问题或者链接到已存在的 issue
23 | - type: textarea
24 | id: solution-description
25 | validations:
26 | required: true
27 | attributes:
28 | label: 描述解决方案
29 | description: 清晰简明地描述你所想要发生的事情,即解决方案
30 | - type: textarea
31 | id: alternatives
32 | attributes:
33 | label: 描述备选方案
34 | description: 解决该问题的备选方案
35 | - type: textarea
36 | id: additional-info
37 | attributes:
38 | label: 附加信息
39 | description: 添加你认为有必要的信息
40 |
--------------------------------------------------------------------------------
/.github/workflows/auto_close_issues.yml:
--------------------------------------------------------------------------------
1 | name: Check Issues
2 |
3 | on:
4 | issues:
5 | types: [opened]
6 | jobs:
7 | check:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - if: contains(github.event.issue.body, '我正在使用旧版本' )
11 | id: close-old-version
12 | name: Close Issue(template)
13 | uses: peter-evans/close-issue@v3
14 | with:
15 | comment: 请先尝试使用最新版本,如果问题依然存在再提交 issue
--------------------------------------------------------------------------------
/.github/workflows/close_inactive_issues.yml:
--------------------------------------------------------------------------------
1 | name: Close inactive issues
2 | on:
3 | schedule:
4 | - cron: "30 1 * * *"
5 |
6 | jobs:
7 | close-issues:
8 | name: Close inactive issues
9 | runs-on: ubuntu-latest
10 | if: github.repository == 'aaa1115910/bv'
11 | permissions:
12 | issues: write
13 | steps:
14 | - uses: actions/stale@v5
15 | with:
16 | days-before-issue-stale: 60
17 | days-before-issue-close: 14
18 | days-before-pr-stale: -1
19 | stale-issue-label: "过时"
20 | stale-issue-message: "该 issue 已过时,因为它已经超过 60 天没有任何活动"
21 | close-issue-message: "该 issue 已关闭,因为它在被标记为过时后 14 天依旧没有任何活动"
22 | repo-token: ${{ secrets.GITHUB_TOKEN }}
23 | exempt-issue-labels: "bug,新功能,优化,有待讨论,疑难杂症"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | /captures
7 | .externalNativeBuild
8 | .cxx
9 | /signing.properties
10 | /.idea/jarRepositories.xml
11 | /.idea/migrations.xml
12 | /.idea/codeStyles/
13 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libs"]
2 | path = libs
3 | url = https://github.com/aaa1115910/bv-libs.git
4 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | /shelf/
2 | /workspace.xml
3 | /deploymentTargetDropDown.xml
4 | /gradle.xml
5 | /caches
6 | /libraries
7 | /modules.xml
8 | /navEditor.xml
9 | /assetWizardSettings.xml
10 | /misc.xml
11 | /compiler.xml
12 | /inspectionProfiles/Project_Default.xml
13 | /CamelCaseConfigNew.xml
14 | # GitHub Copilot persisted chat sessions
15 | /copilot/chatSessions
16 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 aaa1115910
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 | # BVG
6 | ## Big Video God(大唱神)
7 |
8 | [](https://apilevels.com/#:~:text=Jetpack%20Compose%20requires%20a%20minSdk%20of%2021%20or%20higher)
9 | [](https://github.com/aaa1115910/bv)
10 | [](https://www.123912.com/s/g8Ufjv-OmMih)
11 |
12 | # 该改版是给带键鼠的安卓设备使用的,严禁tv端使用,若有tv端使用者,请在24小时内删除否则后果自负,若有tv端使用需求,请下载官方小电视](https://app.bilibili.com)
13 |
14 |
15 | 该改版是基于原bv,已去除中国地区的使用限制,其他额外功能正在研发中,若觉得卡顿,请使用清浊等app对其进行编译
16 |
17 |
18 |
19 | ---
20 | BVG (Big Video God) 是一款 [哔哩哔哩](https://www.bilibili.com) 的第三方 `Android`
21 | 应用,使用 `Jetpack Compose` 开发,支持 `Android 5.0+`
22 |
23 | # 该版本对于某些低配机型消耗极大,由于技术原因暂时无法优化,若有对此方面的进度则会马上更新
24 |
25 |
26 | # 特色
27 | - :bug: 丰富多样的 Bug
28 | - :children_crossing: 反人类设计
29 | - :art: 异样审美
30 | - :disappointed: 巨难用
31 | - :zap: 卡卡卡卡卡卡卡卡卡卡卡卡卡卡卡卡卡卡卡卡
32 | #
33 | # 安装
34 | BVG[](https://www.123912.com/s/g8Ufjv-OmMih)
35 |
36 | # License
37 | [MIT](LICENSE) © aaa1115910
38 | #
39 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /google-services.json
3 | /release
4 | /r8Test
5 | /debug
--------------------------------------------------------------------------------
/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/debug/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | BVG Debug
4 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/kotlin/de/schnettler/datastore/manager/DataStoreManager.kt:
--------------------------------------------------------------------------------
1 | package de.schnettler.datastore.manager
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.Preferences
5 | import androidx.datastore.preferences.core.edit
6 | import kotlinx.coroutines.flow.first
7 | import kotlinx.coroutines.flow.map
8 |
9 | class DataStoreManager(val dataStore: DataStore) {
10 | val preferenceFlow = dataStore.data
11 |
12 | suspend fun getPreference(preferenceEntry: PreferenceRequest) =
13 | preferenceFlow.first()[preferenceEntry.key] ?: preferenceEntry.defaultValue
14 |
15 | fun getPreferenceFlow(request: PreferenceRequest) =
16 | preferenceFlow.map {
17 | it[request.key] ?: request.defaultValue
18 | }
19 |
20 | suspend fun editPreference(key: Preferences.Key, newValue: T) {
21 | dataStore.edit { preferences ->
22 | preferences[key] = newValue
23 | }
24 | }
25 |
26 | suspend fun clearPreferences() {
27 | dataStore.edit { preferences -> preferences.clear() }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/de/schnettler/datastore/manager/PreferenceRequest.kt:
--------------------------------------------------------------------------------
1 | package de.schnettler.datastore.manager
2 |
3 | import androidx.datastore.preferences.core.Preferences
4 |
5 | open class PreferenceRequest(
6 | val key: Preferences.Key,
7 | val defaultValue: T,
8 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/pgc/PgcIndexActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.pgc
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
9 | import dev.aaa1115910.bv.screen.main.pgc.PgcIndexScreen
10 | import dev.aaa1115910.bv.ui.theme.BVTheme
11 |
12 | class PgcIndexActivity : ComponentActivity() {
13 | companion object {
14 | fun actionStart(
15 | context: Context,
16 | pgcType: PgcType
17 | ) {
18 | context.startActivity(
19 | Intent(context, PgcIndexActivity::class.java).apply {
20 | putExtra("pgcType", pgcType.ordinal)
21 | }
22 | )
23 | }
24 | }
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | setContent {
29 | BVTheme {
30 | PgcIndexScreen()
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/pgc/anime/AnimeTimelineActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.pgc.anime
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.main.pgc.anime.AnimeTimelineScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class AnimeTimelineActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | AnimeTimelineScreen()
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/search/SearchInputActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.search
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.runtime.remember
7 | import androidx.compose.ui.focus.FocusRequester
8 | import dev.aaa1115910.bv.screen.search.SearchInputScreen
9 | import dev.aaa1115910.bv.ui.theme.BVTheme
10 |
11 | class SearchInputActivity : ComponentActivity() {
12 | override fun onCreate(savedInstanceState: Bundle?) {
13 | super.onCreate(savedInstanceState)
14 | setContent {
15 | val defaultFocusRequester = remember { FocusRequester() }
16 | BVTheme {
17 | SearchInputScreen(defaultFocusRequester = defaultFocusRequester)
18 | }
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/search/SearchResultActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.search
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.bv.screen.search.SearchResultScreen
9 | import dev.aaa1115910.bv.ui.theme.BVTheme
10 |
11 | class SearchResultActivity : ComponentActivity() {
12 | companion object {
13 | fun actionStart(context: Context, keyword: String, enableProxy: Boolean) {
14 | context.startActivity(
15 | Intent(context, SearchResultActivity::class.java).apply {
16 | putExtra("keyword", keyword)
17 | putExtra("enableProxy", enableProxy)
18 | }
19 | )
20 | }
21 | }
22 |
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 | setContent {
26 | BVTheme {
27 | SearchResultScreen()
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/settings/LogsActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.settings
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.settings.LogsScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class LogsActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | LogsScreen()
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/settings/MediaCodecActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.settings
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.settings.MediaCodecScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class MediaCodecActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | MediaCodecScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/settings/SettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.settings
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.settings.SettingsScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class SettingsActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | SettingsScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/settings/SpeedTestActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.settings
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.settings.SpeedTestScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class SpeedTestActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | SpeedTestScreen()
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/FavoriteActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.user.FavoriteScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class FavoriteActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | FavoriteScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/FollowActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.user.FollowScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class FollowActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | FollowScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/FollowingSeasonActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.user.FollowingSeasonScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class FollowingSeasonActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | FollowingSeasonScreen()
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/HistoryActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.user.HistoryScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class HistoryActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | HistoryScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/LoginActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.login.LoginScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class LoginActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | LoginScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/ToViewActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | // import dev.aaa1115910.bv.screen.user.HistoryScreen
7 | import dev.aaa1115910.bv.screen.user.ToViewScreen
8 | import dev.aaa1115910.bv.ui.theme.BVTheme
9 |
10 | class ToViewActivity : ComponentActivity() {
11 | override fun onCreate(savedInstanceState: Bundle?) {
12 | super.onCreate(savedInstanceState)
13 | setContent {
14 | BVTheme {
15 | // HistoryScreen()
16 | ToViewScreen()
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/UserInfoActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.user.UserInfoScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class UserInfoActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | UserInfoScreen()
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/UserLockSettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.bv.screen.user.lock.UserLockSettingsScreen
9 | import dev.aaa1115910.bv.ui.theme.BVTheme
10 |
11 | class UserLockSettingsActivity : ComponentActivity() {
12 |
13 | companion object {
14 | fun actionStart(
15 | context: Context,
16 | uid: Long
17 | ) {
18 | context.startActivity(
19 | Intent(context, UserLockSettingsActivity::class.java).apply {
20 | putExtra("uid", uid)
21 | }
22 | )
23 | }
24 | }
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | setContent {
29 | BVTheme {
30 | UserLockSettingsScreen()
31 | }
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/user/UserSwitchActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.user
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import dev.aaa1115910.bv.screen.user.UserSwitchScreen
7 | import dev.aaa1115910.bv.ui.theme.BVTheme
8 |
9 | class UserSwitchActivity : ComponentActivity() {
10 | override fun onCreate(savedInstanceState: Bundle?) {
11 | super.onCreate(savedInstanceState)
12 | setContent {
13 | BVTheme {
14 | UserSwitchScreen()
15 | }
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/video/SeasonInfoActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.video
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.bv.entity.proxy.ProxyArea
9 | import dev.aaa1115910.bv.screen.SeasonInfoScreen
10 | import dev.aaa1115910.bv.ui.theme.BVTheme
11 |
12 | class SeasonInfoActivity : ComponentActivity() {
13 | companion object {
14 | fun actionStart(
15 | context: Context,
16 | epId: Int? = null,
17 | seasonId: Int? = null,
18 | proxyArea: ProxyArea = ProxyArea.MainLand
19 | ) {
20 | context.startActivity(
21 | Intent(context, SeasonInfoActivity::class.java).apply {
22 | epId?.let { putExtra("epid", epId) }
23 | seasonId?.let { putExtra("seasonid", seasonId) }
24 | putExtra("proxy_area", proxyArea.ordinal)
25 | }
26 | )
27 | }
28 | }
29 |
30 | override fun onCreate(savedInstanceState: Bundle?) {
31 | super.onCreate(savedInstanceState)
32 | setContent {
33 | BVTheme {
34 | SeasonInfoScreen()
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/video/TagActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.video
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.bv.screen.TagScreen
9 | import dev.aaa1115910.bv.ui.theme.BVTheme
10 |
11 | class TagActivity : ComponentActivity() {
12 | companion object {
13 | fun actionStart(context: Context, tagId: Int, tagName: String) {
14 | context.startActivity(
15 | Intent(context, TagActivity::class.java).apply {
16 | putExtra("tagId", tagId)
17 | putExtra("tagName", tagName)
18 | }
19 | )
20 | }
21 | }
22 |
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 | setContent {
26 | BVTheme {
27 | TagScreen()
28 | }
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/video/UpInfoActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.video
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.bv.screen.user.UpSpaceScreen
9 | import dev.aaa1115910.bv.ui.theme.BVTheme
10 |
11 | class UpInfoActivity : ComponentActivity() {
12 | companion object {
13 | fun actionStart(context: Context, mid: Long, name: String) {
14 | context.startActivity(
15 | Intent(context, UpInfoActivity::class.java).apply {
16 | putExtra("mid", mid)
17 | putExtra("name", name)
18 | }
19 | )
20 | }
21 | }
22 |
23 | override fun onCreate(savedInstanceState: Bundle?) {
24 | super.onCreate(savedInstanceState)
25 | setContent {
26 | BVTheme {
27 | UpSpaceScreen()
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/activities/video/VideoInfoActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.activities.video
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.activity.ComponentActivity
7 | import androidx.activity.compose.setContent
8 | import dev.aaa1115910.bv.entity.proxy.ProxyArea
9 | import dev.aaa1115910.bv.screen.VideoInfoScreen
10 | import dev.aaa1115910.bv.ui.theme.BVTheme
11 |
12 | class VideoInfoActivity : ComponentActivity() {
13 | companion object {
14 | fun actionStart(
15 | context: Context, aid: Long,
16 | fromSeason: Boolean = false,
17 | proxyArea: ProxyArea = ProxyArea.MainLand
18 | ) {
19 | context.startActivity(
20 | Intent(context, VideoInfoActivity::class.java).apply {
21 | putExtra("aid", aid)
22 | putExtra("fromSeason", fromSeason)
23 | putExtra("proxy_area", proxyArea.ordinal)
24 | }
25 | )
26 | }
27 | }
28 |
29 | override fun onCreate(savedInstanceState: Bundle?) {
30 | super.onCreate(savedInstanceState)
31 | setContent {
32 | BVTheme {
33 | VideoInfoScreen()
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/component/BottomTip.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.component
2 |
3 | import androidx.compose.foundation.layout.Column
4 | import androidx.compose.foundation.layout.height
5 | import androidx.compose.material.icons.Icons
6 | import androidx.compose.material.icons.outlined.Info
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.unit.dp
10 | import androidx.tv.material3.Icon
11 | import androidx.tv.material3.MaterialTheme
12 | import androidx.tv.material3.Text
13 |
14 | @Composable
15 | fun BottomTip(
16 | modifier: Modifier = Modifier,
17 | text: String
18 | ) {
19 | Column(
20 | modifier = modifier
21 | ) {
22 | Icon(
23 | modifier = Modifier.height(48.dp),
24 | imageVector = Icons.Outlined.Info,
25 | contentDescription = null,
26 | tint = MaterialTheme.colorScheme.onSurface
27 | )
28 | Text(
29 | text = text.replace("\n", "\n\n"),
30 | style = MaterialTheme.typography.bodySmall
31 | )
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/component/LoadingTip.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.component
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Row
5 | import androidx.compose.foundation.layout.size
6 | import androidx.compose.material3.CircularProgressIndicator
7 | import androidx.compose.runtime.Composable
8 | import androidx.compose.ui.Alignment
9 | import androidx.compose.ui.Modifier
10 | import androidx.compose.ui.graphics.Color
11 | import androidx.compose.ui.res.stringResource
12 | import androidx.compose.ui.tooling.preview.Preview
13 | import androidx.compose.ui.unit.dp
14 | import androidx.tv.material3.Text
15 | import dev.aaa1115910.bv.R
16 |
17 | @Composable
18 | fun LoadingTip(
19 | modifier: Modifier = Modifier
20 | ) {
21 | Row(
22 | modifier = modifier,
23 | verticalAlignment = Alignment.CenterVertically,
24 | horizontalArrangement = Arrangement.spacedBy(8.dp)
25 | ) {
26 | CircularProgressIndicator(
27 | modifier = Modifier.size(36.dp)
28 | )
29 | Text(
30 | text = stringResource(id = R.string.loading),
31 | color = Color.White
32 | )
33 | }
34 | }
35 |
36 | @Preview
37 | @Composable
38 | private fun LoadingTipPreview() {
39 | LoadingTip()
40 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/component/UpIcon.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.component
2 |
3 | import androidx.compose.foundation.layout.Row
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Alignment
6 | import androidx.compose.ui.Modifier
7 | import androidx.compose.ui.graphics.Color
8 | import androidx.compose.ui.res.painterResource
9 | import androidx.compose.ui.tooling.preview.Preview
10 | import androidx.tv.material3.Icon
11 | import androidx.tv.material3.MaterialTheme
12 | import androidx.tv.material3.Text
13 | import dev.aaa1115910.bv.R
14 | import dev.aaa1115910.bv.ui.theme.BVTheme
15 |
16 | @Composable
17 | fun UpIcon(
18 | modifier: Modifier = Modifier,
19 | color: Color = MaterialTheme.colorScheme.onSurface
20 | ) {
21 | Icon(
22 | modifier = modifier,
23 | painter = painterResource(id = R.drawable.ic_up),
24 | contentDescription = null,
25 | tint = color
26 | )
27 | }
28 |
29 | @Preview
30 | @Composable
31 | fun UpIconPreview() {
32 | BVTheme {
33 | Row(
34 | verticalAlignment = Alignment.CenterVertically
35 | ) {
36 | UpIcon()
37 | Text(text = "bishi")
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/component/controllers/GoBackHistoryTip.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.component.controllers
2 |
3 | import androidx.compose.foundation.layout.padding
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import androidx.compose.ui.graphics.Color
7 | import androidx.compose.ui.unit.dp
8 | import androidx.tv.material3.MaterialTheme
9 | import androidx.tv.material3.Surface
10 | import androidx.tv.material3.SurfaceDefaults
11 | import androidx.tv.material3.Text
12 | import dev.aaa1115910.bv.util.formatMinSec
13 |
14 | @Composable
15 | fun GoBackHistoryTip(
16 | modifier: Modifier = Modifier,
17 | played: Int
18 | ) {
19 | Surface(
20 | modifier = modifier,
21 | colors = SurfaceDefaults.colors(
22 | containerColor = Color.Black.copy(alpha = 0.6f)
23 | )
24 | ) {
25 | Text(
26 | modifier = Modifier.padding(8.dp),
27 | text = "上次播放到 “${played.toLong().formatMinSec()}”,按下确认键返回",
28 | style = MaterialTheme.typography.titleLarge
29 | )
30 | }
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/component/settings/SettingListItem.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.component.settings
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.getValue
5 | import androidx.compose.runtime.mutableStateOf
6 | import androidx.compose.runtime.remember
7 | import androidx.compose.runtime.setValue
8 | import androidx.compose.ui.Modifier
9 | import androidx.compose.ui.focus.onFocusChanged
10 | import androidx.tv.material3.ListItem
11 | import androidx.tv.material3.Text
12 |
13 | @Composable
14 | fun SettingListItem(
15 | modifier: Modifier = Modifier,
16 | title: String,
17 | supportText: String,
18 | defaultHasFocus: Boolean = false,
19 | onClick: () -> Unit
20 | ) {
21 | var hasFocus by remember { mutableStateOf(defaultHasFocus) }
22 |
23 | ListItem(
24 | modifier = modifier.onFocusChanged { hasFocus = it.hasFocus },
25 | headlineContent = { Text(text = title) },
26 | supportingContent = { Text(text = supportText) },
27 | trailingContent = { },
28 | onClick = onClick,
29 | selected = false
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/dao/SearchHistoryDao.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Delete
5 | import androidx.room.Insert
6 | import androidx.room.Query
7 | import androidx.room.Update
8 | import dev.aaa1115910.bv.entity.db.SearchHistoryDB
9 |
10 | @Dao
11 | interface SearchHistoryDao {
12 | @Query("SELECT * FROM search_history")
13 | suspend fun getAll(): List
14 |
15 | @Query("SELECT * FROM search_history ORDER BY search_date DESC LIMIT :count")
16 | suspend fun getHistories(count: Int): List
17 |
18 | @Query("SELECT * FROM search_history WHERE keyword = :keyword LIMIT 1")
19 | suspend fun findHistory(keyword: String): SearchHistoryDB?
20 |
21 | @Insert
22 | suspend fun insert(vararg searchHistoryDB: SearchHistoryDB)
23 |
24 | @Delete
25 | suspend fun delete(vararg searchHistoryDB: SearchHistoryDB)
26 |
27 | @Update
28 | suspend fun update(searchHistoryDB: SearchHistoryDB)
29 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/dao/UserDao.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.dao
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Delete
5 | import androidx.room.Insert
6 | import androidx.room.Query
7 | import androidx.room.Update
8 | import dev.aaa1115910.bv.entity.db.UserDB
9 |
10 | @Dao
11 | interface UserDao {
12 | @Query("SELECT * FROM user")
13 | suspend fun getAll(): List
14 |
15 | @Query("SELECT * FROM user WHERE uid = :uid LIMIT 1")
16 | suspend fun findUserByUid(uid: Long): UserDB?
17 |
18 | @Insert
19 | suspend fun insert(vararg userDB: UserDB)
20 |
21 | @Delete
22 | suspend fun delete(vararg userDB: UserDB)
23 |
24 | @Update
25 | suspend fun update(userDB: UserDB)
26 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/Audio.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity
2 |
3 | import android.content.Context
4 | import dev.aaa1115910.bv.R
5 |
6 | enum class Audio(val code: Int, private val strRes: Int) {
7 | A64K(30216, R.string.audio_64k),
8 | A132K(30232, R.string.audio_132k),
9 | A192K(30280, R.string.audio_192k),
10 | ADolbyAtoms(30250, R.string.audio_dolby_atoms),
11 | AHiRes(30251, R.string.audio_hi_res);
12 |
13 | companion object {
14 | fun fromCode(code: Int) = runCatching {
15 | entries.find { it.code == code }
16 | }.getOrDefault(A64K)
17 | }
18 |
19 | fun getDisplayName(context: Context) = context.getString(strRes)
20 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/DanmakuSize.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity
2 |
3 | enum class DanmakuSize(val scale: Float) {
4 | S1(0.25f), S2(0.5f), S3(0.6f), S4(0.7f), S5(0.8f), S6(0.9f), S7(1f),
5 | S8(1.1f), S9(1.2f), S10(1.3f), S11(1.4f), S12(1.5f), S13(2f);
6 |
7 | companion object {
8 | fun fromOrdinal(ordinal: Int) = runCatching { entries[ordinal] }
9 | .getOrDefault(S2)
10 | }
11 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/DanmakuTransparency.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity
2 |
3 | enum class DanmakuTransparency(val transparency: Float) {
4 | T1(1f), T2(0.9f), T3(0.8f), T4(0.7f), T5(0.6f),
5 | T6(0.5f), T7(0.3f), T8(0.2f), T9(0.1f);
6 |
7 | companion object {
8 | fun fromOrdinal(ordinal: Int) = runCatching { entries[ordinal] }
9 | .getOrDefault(T1)
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/PlayerType.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity
2 |
3 | enum class PlayerType {
4 | Media3
5 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/VideoAspectRatio.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity
2 |
3 | import android.content.Context
4 | import dev.aaa1115910.bv.R
5 |
6 | enum class VideoAspectRatio(private val strRes: Int) {
7 | Default(R.string.video_aspect_ratio_default),
8 | FourToThree(R.string.video_aspect_ratio_four_to_three),
9 | SixteenToNine(R.string.video_aspect_ratio_sixteen_to_nine);
10 |
11 | fun getDisplayName(context: Context) = context.getString(strRes)
12 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/carddata/SeasonCardData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity.carddata
2 |
3 | import dev.aaa1115910.biliapi.http.entity.search.SearchMediaResult
4 | import dev.aaa1115910.bv.util.ImageSize
5 | import dev.aaa1115910.bv.util.resizedImageUrl
6 |
7 | data class SeasonCardData(
8 | val seasonId: Int,
9 | val title: String,
10 | val subTitle: String? = null,
11 | val cover: String,
12 | val rating: String? = null,
13 | val badge: SearchMediaResult.Badge? = null,
14 | ) {
15 | companion object {
16 | fun fromPgcItem(pgcItem: dev.aaa1115910.biliapi.entity.pgc.PgcItem): SeasonCardData {
17 | return SeasonCardData(
18 | seasonId = pgcItem.seasonId,
19 | title = pgcItem.title,
20 | subTitle = pgcItem.subTitle,
21 | cover = pgcItem.cover.resizedImageUrl(ImageSize.SeasonCoverThumbnail),
22 | rating = pgcItem.rating,
23 | badge = null
24 | )
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/carddata/VideoCardData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity.carddata
2 |
3 | import dev.aaa1115910.bv.util.formatMinSec
4 |
5 | data class VideoCardData(
6 | val avid: Long,
7 | val title: String,
8 | val cover: String,
9 | val upName: String,
10 | val reason: String = "",
11 | val play: Int? = null,
12 | var playString: String = "",
13 | val danmaku: Int? = null,
14 | var danmakuString: String = "",
15 | val time: Long? = null,
16 | var timeString: String = "",
17 | val jumpToSeason: Boolean = false,
18 | val epId: Int? = null
19 | ) {
20 | init {
21 | play?.let {
22 | playString = if (it >= 10000) "${it / 10000}万" else "$it"
23 | }
24 | danmaku?.let {
25 | danmakuString = if (it >= 10000) "${it / 10000}万" else "$it"
26 | }
27 | time?.let {
28 | timeString = if (it > 0) it.formatMinSec() else ""
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/db/SearchHistoryDB.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity.db
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 | import java.util.Date
7 |
8 | @Entity(tableName = "search_history")
9 | data class SearchHistoryDB(
10 | @PrimaryKey(autoGenerate = true) val id: Int? = null,
11 | @ColumnInfo(name = "keyword") val keyword: String,
12 | @ColumnInfo(name = "search_date") var searchDate: Date = Date(),
13 | )
14 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/db/UserDB.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity.db
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 |
7 | @Entity(tableName = "user")
8 |
9 | data class UserDB(
10 | @PrimaryKey(autoGenerate = true) val id: Int? = null,
11 | @ColumnInfo(name = "uid") val uid: Long,
12 | @ColumnInfo(name = "username") var username: String,
13 | @ColumnInfo(name = "avatar") var avatar: String,
14 | @ColumnInfo(name = "auth") var auth: String,
15 | @ColumnInfo(name = "lock", defaultValue = "") var lock: String = "",
16 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/entity/proxy/ProxyArea.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.entity.proxy
2 |
3 | import dev.aaa1115910.bv.util.Prefs
4 | import io.github.oshai.kotlinlogging.KotlinLogging
5 |
6 | enum class ProxyArea {
7 | MainLand, HongKong, TaiWan;
8 |
9 | companion object {
10 | private val logger = KotlinLogging.logger { }
11 | fun checkProxyArea(title: String): ProxyArea {
12 | val enableProxy = Prefs.enableProxy
13 | val proxyArea = when {
14 | !enableProxy -> MainLand
15 | title.contains(Regex("僅.*港")) -> HongKong
16 | title.contains(Regex("僅.*台")) -> TaiWan
17 | else -> MainLand
18 | }
19 | if (enableProxy) logger.debug { "Check proxy area: $title->$proxyArea" }
20 | return proxyArea
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/repository/VideoInfoRepository.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.repository
2 |
3 | class VideoInfoRepository {
4 | val videoList = mutableListOf()
5 | }
6 |
7 | data class VideoListItem(
8 | val aid: Long,
9 | val cid: Long,
10 | val epid: Int? = null,
11 | val seasonId: Int? = null,
12 | val title: String,
13 | val index: Int,
14 | val isEpisode: Boolean
15 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/login/LoginScreen.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.login
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.ui.Modifier
5 |
6 | @Composable
7 | fun LoginScreen(
8 | modifier: Modifier = Modifier
9 | ) {
10 | /*when (Prefs.apiType) {
11 | ApiType.Http -> {
12 | WebQRLoginContent(modifier)
13 | }
14 |
15 | ApiType.GRPC -> {
16 | SmsLoginContent(modifier)
17 | }
18 | }*/
19 | AppQRLoginContent(modifier)
20 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/AnimalContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun AnimalContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { AnimalChildRegionButtons() },
17 | )
18 | }
19 |
20 | @Composable
21 | fun AnimalChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.AnimalCat, UgcType.AnimalDog, UgcType.AnimalReptiles, UgcType.AnimalWildAnima,
24 | UgcType.AnimalSecondEdition, UgcType.AnimalComposite
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/CarContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun CarContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { CarChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun CarChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.CarKnowledge, UgcType.CarStrategy, UgcType.CarNewEnergyVehicle,
24 | UgcType.CarRacing, UgcType.CarModifiedVehicle, UgcType.CarMotorcycle,
25 | UgcType.CarTouringCar, UgcType.CarLife
26 | )
27 |
28 | UgcChildRegionButtons(
29 | modifier = modifier.fillMaxWidth(),
30 | childUgcTypes = ugcTypes
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/CinephileContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun CinephileContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { CinephileChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun CinephileChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.CinephileCinecism, UgcType.CinephileNibtage, UgcType.CinephileMashup,
24 | UgcType.CinephileAiImagine, UgcType.CinephileTrailerInfo, UgcType.CinephileShortPlay,
25 | UgcType.CinephileShortFilm, UgcType.CinephileComperhensive
26 | )
27 |
28 | UgcChildRegionButtons(
29 | modifier = modifier.fillMaxWidth(),
30 | childUgcTypes = ugcTypes
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/DanceContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun DanceContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { DanceChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun DanceChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.DanceOtaku, UgcType.DanceHiphop, UgcType.DanceStar, UgcType.DanceChina,
24 | UgcType.DanceGestures, UgcType.DanceThreeD, UgcType.DanceDemo
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/DougaContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun DougaContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { DougaChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun DougaChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.DougaMad, UgcType.DougaMmd, UgcType.DougaHandDrawn, UgcType.DougaVoice,
24 | UgcType.DougaGarageKit, UgcType.DougaTokusatsu, UgcType.DougaAcgnTalks, UgcType.DougaOther
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/EntContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun EntContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { EntChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun EntChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.EntTalker, UgcType.EntCpRecommendation, UgcType.EntBeauty, UgcType.EntFans,
24 | UgcType.EntEntertainmentNews, UgcType.EntCelebrity, UgcType.EntVariety
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/FashionContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun FashionContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { FashionChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun FashionChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.FashionMakeup, UgcType.FashionCos, UgcType.FashionClothing, UgcType.FashionCatwalk
24 | )
25 |
26 | UgcChildRegionButtons(
27 | modifier = modifier.fillMaxWidth(),
28 | childUgcTypes = ugcTypes
29 | )
30 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/FoodContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun FoodContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { FoodChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun FoodChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.FoodMake, UgcType.FoodDetective, UgcType.FoodMeasurement,
24 | UgcType.FoodRural, UgcType.FoodRecord
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/GameContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun GameContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { GameChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun GameChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.GameStandAlone, UgcType.GameESports, UgcType.GameMobile, UgcType.GameOnline,
24 | UgcType.GameBoard, UgcType.GameGmv, UgcType.GameMusic, UgcType.GameMugen
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/InformationContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun InformationContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { InformationChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun InformationChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.InformationHotspot, UgcType.InformationGlobal,
24 | UgcType.InformationSocial, UgcType.InformationMultiple
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/KichikuContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun KichikuContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { KichikuChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun KichikuChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.KichikuGuide, UgcType.KichikuMad, UgcType.KichikuManualVocaloid,
24 | UgcType.KichikuTheatre, UgcType.KichikuCourse
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/KnowledgeContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun KnowledgeContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { KnowledgeChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun KnowledgeChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.KnowledgeScience, UgcType.KnowledgeSocialScience, UgcType.KnowledgeHumanity,
24 | UgcType.KnowledgeBusiness, UgcType.KnowledgeCampus, UgcType.KnowledgeCareer,
25 | UgcType.KnowledgeDesign, UgcType.KnowledgeSkill
26 | )
27 |
28 | UgcChildRegionButtons(
29 | modifier = modifier.fillMaxWidth(),
30 | childUgcTypes = ugcTypes
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/LifeContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun LifeContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { LifeChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun LifeChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.LifeFunny, UgcType.LifeParenting, UgcType.LifeTravel, UgcType.LiseRuralLife,
24 | UgcType.LifeHome, UgcType.LifeHandMake, UgcType.LifePainting, UgcType.LifeDaily
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/MuiscContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun MusicContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { MusicChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun MusicChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.MusicOriginal, UgcType.MusicLive, UgcType.MusicCover, UgcType.MusicPerform,
24 | UgcType.MusicCommentary, UgcType.MusicVocaloidUtau, UgcType.MusicMv, UgcType.MusicFanVideos,
25 | UgcType.MusicAiMusic, UgcType.MusicRadio, UgcType.MusicTutorial, UgcType.MusicOther
26 | )
27 |
28 | UgcChildRegionButtons(
29 | modifier = modifier.fillMaxWidth(),
30 | childUgcTypes = ugcTypes
31 | )
32 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/SportsContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun SportsContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { SportsChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun SportsChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.SportsBasketball, UgcType.SportsFootball, UgcType.SportsAerobics,
24 | UgcType.SportsAthletic, UgcType.SportsCulture, UgcType.SportsComprehensive
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/screen/main/ugc/TechContent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.screen.main.ugc
2 |
3 | import androidx.compose.foundation.layout.fillMaxWidth
4 | import androidx.compose.runtime.Composable
5 | import androidx.compose.ui.Modifier
6 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
7 |
8 | @Composable
9 | fun TechContent(
10 | modifier: Modifier = Modifier,
11 | state: UgcScaffoldState
12 | ) {
13 | UgcRegionScaffold(
14 | modifier = modifier,
15 | state = state,
16 | childRegionButtons = { TechChildRegionButtons() }
17 | )
18 | }
19 |
20 | @Composable
21 | fun TechChildRegionButtons(modifier: Modifier = Modifier) {
22 | val ugcTypes = listOf(
23 | UgcType.TechDigital, UgcType.TechApplication, UgcType.TechComputerTech,
24 | UgcType.TechIndustry, UgcType.TechDiy
25 | )
26 |
27 | UgcChildRegionButtons(
28 | modifier = modifier.fillMaxWidth(),
29 | childUgcTypes = ugcTypes
30 | )
31 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/util/EnumExtends.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.util
2 |
3 | import android.content.Context
4 | import dev.aaa1115910.biliapi.entity.season.FollowingSeasonStatus
5 | import dev.aaa1115910.biliapi.entity.season.FollowingSeasonType
6 | import dev.aaa1115910.bv.R
7 |
8 | fun FollowingSeasonStatus.getDisplayName(context: Context) = when (this) {
9 | FollowingSeasonStatus.All -> context.getString(R.string.following_season_status_all)
10 | FollowingSeasonStatus.Want -> context.getString(R.string.following_season_status_want)
11 | FollowingSeasonStatus.Watching -> context.getString(R.string.following_season_status_watching)
12 | FollowingSeasonStatus.Watched -> context.getString(R.string.following_season_status_watched)
13 | }
14 |
15 | fun FollowingSeasonType.getDisplayName(context: Context) = when (this) {
16 | FollowingSeasonType.Bangumi -> context.getString(R.string.following_season_type_bangumi)
17 | FollowingSeasonType.Cinema -> context.getString(R.string.following_season_type_film_and_television)
18 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/util/FirebaseUtil.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.util
2 |
3 | import android.content.Context
4 | import com.google.firebase.FirebaseApp
5 | import com.google.firebase.analytics.ktx.analytics
6 | import com.google.firebase.crashlytics.ktx.crashlytics
7 | import com.google.firebase.ktx.Firebase
8 |
9 | object FirebaseUtil {
10 | private var initialized = false
11 |
12 | fun init(context: Context) {
13 | initialized = FirebaseApp.initializeApp(context) != null
14 | }
15 |
16 | fun log(msg: String) {
17 | if (!initialized) return
18 | Firebase.crashlytics.log(msg)
19 | }
20 |
21 | fun recordException(throwable: Throwable) {
22 | if (!initialized) return
23 | Firebase.crashlytics.recordException(throwable)
24 | }
25 |
26 | fun setCrashlyticsCollectionEnabled(enable: Boolean) {
27 | if (!initialized) return
28 | Firebase.crashlytics.setCrashlyticsCollectionEnabled(enable)
29 | Firebase.analytics.setAnalyticsCollectionEnabled(enable)
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/util/ImageExtends.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.util
2 |
3 | fun String.resizedImageUrl(size: ImageSize): String {
4 | return when (size) {
5 | ImageSize.Default -> this
6 | else -> "$this@${size.sizeString}.webp"
7 | }
8 | }
9 |
10 | enum class ImageSize(val sizeString: String) {
11 | Default(""),
12 | Cover("180h_288w_1c"),
13 | SmallVideoCardCover("400h_640w_1c"),
14 | SeasonCoverThumbnail("466h_622w")
15 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/util/PgcTypeExtends.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.util
2 |
3 | import android.content.Context
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 | import dev.aaa1115910.bv.R
6 |
7 | fun PgcType.getDisplayName(context: Context) = when (this) {
8 | PgcType.Anime -> R.string.pgc_type_anime
9 | PgcType.GuoChuang -> R.string.pgc_type_guochuang
10 | PgcType.Movie -> R.string.pgc_type_movie
11 | PgcType.Documentary -> R.string.pgc_type_documentary
12 | PgcType.Tv -> R.string.pgc_type_tv
13 | PgcType.Variety -> R.string.pgc_type_variety
14 | }.stringRes(context)
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/viewmodel/pgc/PgcAnimeViewModel.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.viewmodel.pgc
2 |
3 | import dev.aaa1115910.biliapi.repositories.PgcRepository
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 |
6 | class PgcAnimeViewModel(
7 | override val pgcRepository: PgcRepository
8 | ) : PgcViewModel(
9 | pgcRepository = pgcRepository,
10 | pgcType = PgcType.Anime
11 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/viewmodel/pgc/PgcDocumentaryViewModel.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.viewmodel.pgc
2 |
3 | import dev.aaa1115910.biliapi.repositories.PgcRepository
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 |
6 | class PgcDocumentaryViewModel(
7 | override val pgcRepository: PgcRepository
8 | ) : PgcViewModel(
9 | pgcRepository = pgcRepository,
10 | pgcType = PgcType.Documentary
11 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/viewmodel/pgc/PgcGuoChuangViewModel.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.viewmodel.pgc
2 |
3 | import dev.aaa1115910.biliapi.repositories.PgcRepository
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 |
6 | class PgcGuoChuangViewModel(
7 | override val pgcRepository: PgcRepository
8 | ) : PgcViewModel(
9 | pgcRepository = pgcRepository,
10 | pgcType = PgcType.GuoChuang
11 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/viewmodel/pgc/PgcMovieViewModel.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.viewmodel.pgc
2 |
3 | import dev.aaa1115910.biliapi.repositories.PgcRepository
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 |
6 | class PgcMovieViewModel(
7 | override val pgcRepository: PgcRepository
8 | ) : PgcViewModel(
9 | pgcRepository = pgcRepository,
10 | pgcType = PgcType.Movie
11 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/viewmodel/pgc/PgcTvViewModel.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.viewmodel.pgc
2 |
3 | import dev.aaa1115910.biliapi.repositories.PgcRepository
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 |
6 | class PgcTvViewModel(
7 | override val pgcRepository: PgcRepository
8 | ) : PgcViewModel(
9 | pgcRepository = pgcRepository,
10 | pgcType = PgcType.Tv
11 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/dev/aaa1115910/bv/viewmodel/pgc/PgcVarietyViewModel.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.viewmodel.pgc
2 |
3 | import dev.aaa1115910.biliapi.repositories.PgcRepository
4 | import dev.aaa1115910.biliapi.entity.pgc.PgcType
5 |
6 | class PgcVarietyViewModel(
7 | override val pgcRepository: PgcRepository
8 | ) : PgcViewModel(
9 | pgcRepository = pgcRepository,
10 | pgcType = PgcType.Variety
11 | )
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_banner.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/drawable/ic_banner.webp
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_banner_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
14 |
19 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_danmaku_count.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_count.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/font/noto_sans_math_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/font/noto_sans_math_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #FFFFFF
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/provider_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/r8Test/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/r8Test/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | BVG R8 Test
4 |
--------------------------------------------------------------------------------
/app/src/test/kotlin/android/util/Log.kt:
--------------------------------------------------------------------------------
1 | package android.util
2 |
3 | class Log {
4 | companion object {
5 | @JvmStatic
6 | fun isLoggable(tag: String, level: Int): Boolean {
7 | return true
8 | }
9 |
10 | @JvmStatic
11 | fun println(priority: Int, tag: String, msg: String): Int {
12 | println("[$tag] $msg")
13 | return 0
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/test/kotlin/dev/aaa1115910/bv/network/GithubApiTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.network
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import kotlin.test.Test
5 |
6 | class GithubApiTest {
7 | @Test
8 | fun `get latest release build`() = runBlocking {
9 | println(GithubApi.getLatestReleaseBuild())
10 | }
11 |
12 | @Test
13 | fun `get latest pre-release build`() = runBlocking {
14 | println(GithubApi.getLatestPreReleaseBuild())
15 | }
16 | }
--------------------------------------------------------------------------------
/bili-api-grpc/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/account/fission/v1/fission.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.account.fission.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | // Fission裂变
8 | service Fission {
9 | // 活动入口
10 | rpc Entrance (EntranceReq) returns (EntranceReply);
11 | // 首页弹窗
12 | rpc Window (WindowReq) returns (WindowReply);
13 | //
14 | rpc Privacy (PrivacyReq) returns (PrivacyReply);
15 | }
16 |
17 | // 动画效果
18 | message AnimateIcon {
19 | // icon文件
20 | string icon = 1;
21 | // 动效json文件
22 | string json = 2;
23 | }
24 |
25 | // 活动入口-响应
26 | message EntranceReply {
27 | // 展示图标
28 | string icon = 1;
29 | // 活动名称
30 | string name = 2;
31 | // 活动跳转链接
32 | string url = 3;
33 | // 动画效果
34 | AnimateIcon animate_icon = 4;
35 | }
36 |
37 | // 活动入口-请求
38 | message EntranceReq {}
39 |
40 | //
41 | message PrivacyReply {
42 | //
43 | string message = 1;
44 | }
45 |
46 | //
47 | message PrivacyReq {
48 | //
49 | string activity_uid = 1;
50 | }
51 |
52 | //首页弹窗-响应
53 | message WindowReply {
54 | // 弹窗类型
55 | // 0:弹窗 1:普通页面
56 | int32 type = 1;
57 | // 跳转链接
58 | string url = 2;
59 | // 上报数据字段
60 | string report_data = 3;
61 | }
62 |
63 | // 首页弹窗-请求
64 | message WindowReq {
65 |
66 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/api/ticket/v1/ticket.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.api.ticket.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | service Ticket {
8 | // 获取鉴权用 Ticket
9 | rpc GetTicket (GetTicketRequest) returns (GetTicketResponse);
10 | }
11 |
12 | //
13 | message GetTicketRequest {
14 | // 包含:
15 | // + x-fingerprint(包含手机各类信息, 使用 datacenter.hakase.protobuf.AndroidDeviceInfo 生成)
16 | // + x-exbadbasket(?)
17 | map context = 1;
18 | // 暂时固定为 ec01
19 | string key_id = 2;
20 | //
21 | bytes sign = 3;
22 | // 暂时留空
23 | string token = 4;
24 | }
25 |
26 | //
27 | message GetTicketResponse {
28 | //
29 | message Context {
30 | //
31 | string v_voucher = 1;
32 | }
33 | // x-bili-ticket
34 | string ticket = 1;
35 | // 有效期起
36 | int64 created_at = 2;
37 | // 有效期
38 | int64 ttl = 3;
39 | //
40 | Context context = 4;
41 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/archive/middleware/v1/preload.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.archive.middleware.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 视频秒开参数
8 | message PlayerArgs {
9 | // 清晰度
10 | int64 qn = 1;
11 | // 流版本
12 | int64 fnver = 2;
13 | // 流类型
14 | int64 fnval = 3;
15 | // 返回url是否强制使用域名
16 | // 0:不强制使用域名 1:http域名 2:https域名
17 | int64 force_host = 4;
18 | // 音量均衡
19 | int64 voice_balance = 5;
20 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/card/v1/ad.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.card.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message AdInfo {
9 | //
10 | int64 creative_id = 1;
11 | //
12 | int32 creative_type = 2;
13 | //
14 | int32 card_type = 3;
15 | //
16 | CreativeContent creative_content = 4;
17 | //
18 | string ad_cb = 5;
19 | //
20 | int64 resource = 6;
21 | //
22 | int32 source = 7;
23 | //
24 | string request_id = 8;
25 | //
26 | bool is_ad = 9;
27 | //
28 | int64 cm_mark = 10;
29 | //
30 | int32 index = 11;
31 | //
32 | bool is_ad_loc = 12;
33 | //
34 | int32 card_index = 13;
35 | //
36 | string client_ip = 14;
37 | //
38 | bytes extra = 15;
39 | //
40 | int32 creative_style = 16;
41 | }
42 |
43 | //
44 | message CreativeContent {
45 | //
46 | string title = 1;
47 | //
48 | string description = 2;
49 | //
50 | int64 video_id = 3;
51 | //
52 | string username = 4;
53 | //
54 | string image_url = 5;
55 | //
56 | string image_md5 = 6;
57 | //
58 | string log_url = 7;
59 | //
60 | string log_md5 = 8;
61 | //
62 | string url = 9;
63 | //
64 | string click_url = 10;
65 | //
66 | string show_url = 11;
67 | }
68 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/card/v1/card.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.card.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/card/v1/single.proto";
8 |
9 | // 卡片信息
10 | message Card {
11 | oneof item {
12 | // 小封面条目
13 | SmallCoverV5 small_cover_v5 = 1;
14 | //
15 | LargeCoverV1 large_cover_v1 = 2;
16 | //
17 | ThreeItemAllV2 three_item_all_v2 = 3;
18 | //
19 | ThreeItemV1 three_item_v1 = 4;
20 | //
21 | HotTopic hot_topic = 5;
22 | //
23 | DynamicHot three_item_h_v5 = 6;
24 | //
25 | MiddleCoverV3 middle_cover_v3 = 7;
26 | //
27 | LargeCoverV4 large_cover_v4 = 8;
28 | // 热门列表顶部按钮
29 | PopularTopEntrance popular_top_entrance = 9;
30 | //
31 | RcmdOneItem rcmd_one_item = 10;
32 | //
33 | SmallCoverV5Ad small_cover_v5_ad = 11;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/download.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.download;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message DownloadSettingsConfig {
11 | //
12 | bilibili.app.distribution.v1.BoolValue enable_download_auto_start = 1;
13 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/dynamic.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.dynamic;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message DynamicAutoPlay {
11 | //
12 | bilibili.app.distribution.v1.Int64Value value = 1;
13 | }
14 |
15 | //
16 | message DynamicDeviceConfig {
17 | //
18 | DynamicAutoPlay auto_play = 1;
19 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/internaldevice.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.internaldevice;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message InternalDeviceConfig {
11 | // 首次启动时间
12 | bilibili.app.distribution.v1.Int64Value fts = 1;
13 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/night.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.night;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message NightSettingsConfig {
11 | //
12 | bilibili.app.distribution.v1.BoolValue is_night_follow_system = 1;
13 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/other.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.other;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message OtherSettingsConfig {
11 | //
12 | bilibili.app.distribution.v1.Int64Value watermark_type = 1;
13 | //
14 | bilibili.app.distribution.v1.Int64Value web_image_quality_type = 2;
15 | //
16 | bilibili.app.distribution.v1.BoolValue enable_read_pasteboard = 3;
17 | //
18 | bilibili.app.distribution.v1.BoolValue paste_auto_jump = 4;
19 | //
20 | bilibili.app.distribution.v1.BoolValue mini_screen_play_when_back = 5;
21 | //
22 | bilibili.app.distribution.v1.BoolValue enable_resume_playing = 6;
23 | //
24 | bilibili.app.distribution.v1.BoolValue enable_wifi_auto_update = 7;
25 | //
26 | bilibili.app.distribution.v1.BoolValue enable_guide_screenshot_share = 8;
27 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/pegasus.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.pegasus;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message FeedModeValue {
11 | //
12 | bilibili.app.distribution.v1.Int64Value value = 1;
13 | }
14 |
15 | //
16 | message PegasusAutoPlay {
17 | //
18 | bilibili.app.distribution.v1.Int64Value single = 1;
19 | //
20 | bilibili.app.distribution.v1.Int64Value double = 2;
21 | //
22 | bilibili.app.distribution.v1.BoolValue single_affected_by_server_side = 3;
23 | //
24 | bilibili.app.distribution.v1.BoolValue double_affected_by_server_side = 4;
25 | }
26 |
27 | //
28 | message PegasusColumnValue {
29 | //
30 | bilibili.app.distribution.v1.Int64Value value = 1;
31 | //
32 | bilibili.app.distribution.v1.BoolValue affected_by_server_side = 2;
33 | }
34 |
35 | //
36 | message PegasusDeviceConfig {
37 | //
38 | PegasusColumnValue column = 1;
39 | //
40 | FeedModeValue mode = 2;
41 | //
42 | PegasusAutoPlay auto_play = 3;
43 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/privacy.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.privacy;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message MidPrivacySettingsConfig {
11 | //
12 | bilibili.app.distribution.v1.BoolValue recommend_to_known = 1;
13 | }
14 |
15 | //
16 | message PrivacySettingsConfig {
17 | //
18 | bilibili.app.distribution.v1.BoolValue ad_recommand_store = 1;
19 | // 传感器权限
20 | bilibili.app.distribution.v1.BoolValue sensor_access = 2;
21 |
22 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/distribution/setting/search.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.distribution.setting.search;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/distribution/v1/distribution.proto";
8 |
9 | //
10 | message SearchAutoPlay {
11 | //
12 | bilibili.app.distribution.v1.Int64Value value = 1;
13 | //
14 | bilibili.app.distribution.v1.BoolValue affected_by_server_side = 2;
15 | }
16 |
17 | //
18 | message SearchDeviceConfig {
19 | //
20 | SearchAutoPlay auto_play = 1;
21 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/dynamic/common/dynamic.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.dynamic.common;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message ItemWHRatio {
9 | //
10 | int32 ratio = 1;
11 | //
12 | int32 width = 2;
13 | //
14 | int32 height = 3;
15 | }
16 |
17 | //
18 | enum WHRatio {
19 | W_H_RATIO_1_1 = 0;
20 | W_H_RATIO_16_9 = 1;
21 | W_H_RATIO_3_4 = 2;
22 | W_H_RATIO_CUSTOM = 3;
23 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/dynamic/v2/opus.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.dynamic.v2;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/app/archive/middleware/v1/preload.proto";
8 | import "bilibili/app/dynamic/v2/dynamic.proto";
9 |
10 | service Opus {
11 | //
12 | rpc OpusDetail (OpusDetailReq) returns (OpusDetailResp);
13 | }
14 |
15 | //
16 | message OpusDetailReq {
17 | //
18 | OpusType opus_type = 1;
19 | //
20 | int64 oid = 2;
21 | //
22 | int64 dyn_type = 3;
23 | //
24 | string share_id = 4;
25 | //
26 | int32 share_mode = 9;
27 | //
28 | int32 local_time = 10;
29 | //
30 | bilibili.app.archive.middleware.v1.PlayerArgs player_args = 11;
31 | //
32 | Config config = 12;
33 | }
34 |
35 | //
36 | message OpusDetailResp {
37 | //
38 | OpusItem opus_item = 1;
39 | }
40 |
41 | //
42 | message OpusItem {
43 | //
44 | int64 opus_id = 1;
45 | //
46 | OpusType opus_type = 2;
47 | //
48 | int64 oid = 3;
49 | //
50 | repeated Module modules = 4;
51 | //
52 | Extend extend = 5;
53 | }
54 |
55 | enum OpusType {
56 | OPUS_TYPE_DYN = 0;
57 | OPUS_TYPE_ARTICLE = 1;
58 | OPUS_TYPE_NOTE = 2;
59 | OPUS_TYPE_WORD = 3;
60 | }
61 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/playerunite/pgcanymodel/PGCAnyModel.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.playerunite.pgcanymodel;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/pgc/gateway/player/v2/playurl.proto";
8 |
9 | message PGCAnyModel {
10 | bilibili.pgc.gateway.player.v2.PlayViewBusinessInfo business = 3;
11 | bilibili.pgc.gateway.player.v2.Event event = 4;
12 | bilibili.pgc.gateway.player.v2.ViewInfo view_info = 5;
13 | bilibili.pgc.gateway.player.v2.PlayAbilityExtConf play_ext_conf = 6;
14 | //bilibili.pgc.gateway.player.v2.PlayExtInfo play_ext_info = 7;
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/playerunite/ugcanymodel/UGCAnyModel.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.playerunite.ugcanymodel;
4 |
5 | option java_multiple_files = true;
6 |
7 | message ButtonStyle {
8 | string text = 1;
9 | string text_color = 2;
10 | string bg_color = 3;
11 | string jump_link = 4;
12 | }
13 |
14 | enum PlayLimitCode {
15 | PLC_UNKNOWN = 0;
16 | PLC_NOTPAYED = 1;
17 | }
18 |
19 | message PlayLimit {
20 | PlayLimitCode code = 1;
21 | string message = 2;
22 | string sub_message = 3;
23 | ButtonStyle button = 4;
24 | }
25 |
26 | message UGCAnyModel {
27 | PlayLimit play_limit = 1;
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/playerunite/v1/playerunite.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.playerunite.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/playershared/playershared.proto";
8 |
9 | import "google/protobuf/any.proto";
10 |
11 | // 统一视频url
12 | service Player {
13 | // 视频地址
14 | rpc PlayViewUnite (PlayViewUniteReq) returns (PlayViewUniteReply);
15 | }
16 |
17 | //
18 | message PlayViewUniteReq {
19 | // 请求资源VOD信息
20 | bilibili.playershared.VideoVod vod = 1;
21 | //
22 | string spmid = 2;
23 | //
24 | string from_spmid = 3;
25 | // 补充信息, 如ep_id等
26 | map extra_content = 4;
27 | //
28 | string bvid = 5;
29 | }
30 |
31 | //
32 | message PlayViewUniteReply {
33 | // 音视频流信息
34 | bilibili.playershared.VodInfo vod_info = 1;
35 | //
36 | bilibili.playershared.PlayArcConf play_arc_conf = 2;
37 | //
38 | bilibili.playershared.PlayDeviceConf play_device_conf = 3;
39 | //
40 | bilibili.playershared.Event event = 4;
41 | // 使用 pgcanymodel / ugcanymodel 进行proto any转换成对应业务码结构体
42 | google.protobuf.Any supplement = 5;
43 | //
44 | bilibili.playershared.PlayArc play_arc = 6;
45 | //
46 | bilibili.playershared.QnTrialInfo qn_trial_info = 7;
47 | //
48 | bilibili.playershared.History history = 8;
49 | //
50 | bilibili.playershared.ViewInfo view_info = 9;
51 | }
52 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/resource/privacy/v1/api.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.resource.privacy.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 隐私
8 | service Privacy {
9 | // 获取隐私设置
10 | rpc PrivacyConfig(NoArgRequest) returns(PrivacyConfigReply);
11 | // 修改隐私设置
12 | rpc SetPrivacyConfig(SetPrivacyConfigRequest) returns(NoReply);
13 | }
14 |
15 | // 空请求
16 | message NoArgRequest{
17 |
18 | }
19 |
20 | // 空响应
21 | message NoReply{
22 |
23 | }
24 |
25 | // 隐私设置
26 | message PrivacyConfigItem {
27 | // 隐私开关类型
28 | PrivacyConfigType privacy_config_type = 1;
29 | //
30 | string title = 2;
31 | // 隐私开关状态
32 | PrivacyConfigState state = 3;
33 | //
34 | string sub_title = 4;
35 | //
36 | string sub_title_uri = 5;
37 | }
38 |
39 | // 获取隐私设置-响应
40 | message PrivacyConfigReply {
41 | // 隐私设置
42 | PrivacyConfigItem privacy_config_item = 1;
43 | }
44 |
45 | // 隐私开关状态
46 | enum PrivacyConfigState {
47 | close = 0; // 关闭
48 | open = 1; // 打开
49 | }
50 |
51 | // 隐私开关类型
52 | enum PrivacyConfigType {
53 | none = 0; //
54 | dynamic_city = 1; // 动态同城
55 | }
56 |
57 | // 修改隐私设置-请求
58 | message SetPrivacyConfigRequest {
59 | // 隐私开关类型
60 | PrivacyConfigType privacy_config_type = 1;
61 | // 隐私开关状态
62 | PrivacyConfigState state = 2;
63 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/show/gateway/v1/service.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.show.gateway.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "bilibili/broadcast/message/main/native.proto";
8 |
9 | //
10 | service AppShow {
11 | // 获取Native页进度数据
12 | rpc GetActProgress (GetActProgressReq) returns (GetActProgressReply);
13 | }
14 |
15 | // 获取Native页进度数据-请求
16 | message GetActProgressReq {
17 | // Native页id
18 | int64 pageID = 1;
19 | // 用户mid
20 | int64 mid = 2;
21 | }
22 |
23 | // 获取Native页进度数据-响应
24 | message GetActProgressReply {
25 | // 进度数据
26 | bilibili.broadcast.message.main.NativePageEvent event = 1;
27 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/show/mixture/v1/mixture.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.show.mixture.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | service Mixture {
9 | //
10 | rpc Widget(WidgetReq) returns (WidgetReply);
11 | }
12 |
13 | //
14 | message RcmdReason {
15 | //
16 | string content = 1;
17 | //
18 | uint32 corner_mark = 2;
19 | }
20 |
21 | //
22 | message WidgetItem {
23 | //
24 | string cover = 1;
25 | //
26 | string view = 2;
27 | //
28 | RcmdReason rcmd_reason = 3;
29 | //
30 | string title = 4;
31 | //
32 | string name = 5;
33 | //
34 | string uri = 6;
35 | //
36 | string goto = 7;
37 | //
38 | int64 id = 8;
39 | //
40 | int32 view_icon = 9;
41 | }
42 |
43 | //
44 | message WidgetReply {
45 | //
46 | repeated WidgetItem item = 1;
47 | }
48 |
49 | //
50 | message WidgetReq {
51 | //
52 | string from_spmid = 1;
53 | //
54 | uint32 page_no = 2;
55 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/show/region/v1/region.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.show.region.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | service Region {
9 | //
10 | rpc Region (RegionReq) returns (RegionReply);
11 | }
12 |
13 | //
14 | message RegionConfig {
15 | //
16 | string scenes_name = 1;
17 | //
18 | string scenes_type = 2;
19 | }
20 |
21 | //
22 | message RegionInfo {
23 | //
24 | int32 tid = 1;
25 | //
26 | int32 reid = 2;
27 | //
28 | string name = 3;
29 | //
30 | string logo = 4;
31 | //
32 | string goto = 5;
33 | //
34 | string param = 6;
35 | //
36 | string uri = 7;
37 | //
38 | int32 type = 8;
39 | //
40 | int32 is_bangumi = 9;
41 | //
42 | repeated RegionInfo children = 10;
43 | //
44 | repeated RegionConfig config = 11;
45 | }
46 |
47 | //
48 | message RegionReply {
49 | //
50 | repeated RegionInfo regions = 1;
51 | }
52 |
53 | //
54 | message RegionReq {
55 | //
56 | string lang = 1;
57 | }
58 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/app/wall/v1/wall.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.app.wall.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 免流规则
8 | service Wall {
9 | // 获取免流规则信息
10 | rpc RuleInfo (RuleRequest) returns (RulesReply);
11 | }
12 |
13 | // 免流规则信息
14 | message RuleInfo {
15 | // 是否支持免流
16 | bool tf = 1;
17 | // 操作模式
18 | // break:无 replace:替换 proxy:代理
19 | string m = 2;
20 | // 操作参数
21 | string a = 3;
22 | // 匹配目标正则
23 | string p = 4;
24 | //
25 | repeated string a_backup = 5;
26 | }
27 |
28 | // 获取免流规则信息-请求
29 | message RuleRequest {}
30 |
31 | // 免流规则信息组
32 | message RulesInfo {
33 | // 免流规则信息
34 | repeated RuleInfo rulesInfo = 1;
35 | }
36 |
37 | // 获取免流规则信息-响应
38 | message RulesReply {
39 | // 各ISP的免流规则信息组
40 | // ISP如: cu ct cm
41 | map rulesInfo = 1;
42 | //
43 | string hash_value = 2;
44 | }
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/editor/notify.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.editor;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | //
10 | service OperationNotify {
11 | //
12 | rpc OperationNotify(google.protobuf.Empty) returns (stream Notify);
13 | }
14 |
15 | message Notify {
16 | // 消息唯一标示
17 | int64 msg_id = 1;
18 | // 消息类型
19 | int32 msg_type = 2;
20 | // 接收方uid
21 | int64 receiver_uid = 3;
22 | //接收方类型
23 | int32 receiver_type = 4;
24 | // 故事的版本
25 | int64 story_version = 5;
26 | // 操作结果的hash值
27 | int64 op_hash = 6;
28 | // 操作产生用户的uid
29 | int64 op_sender = 7;
30 | // patch内容
31 | string op_content = 8;
32 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/esports/notify.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.esports;
4 |
5 | option java_multiple_files = true;
6 |
7 | message Notify {
8 | // cid
9 | int64 cid = 1;
10 | }
11 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/fission/notify.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.fission;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | //
10 | service Fission {
11 | //
12 | rpc GameNotify(google.protobuf.Empty) returns (stream GameNotifyReply);
13 | }
14 |
15 | message GameNotifyReply {
16 | // 类型字段
17 | uint32 type = 1;
18 | // 数据字段
19 | string data = 2;
20 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/main/dm.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.main;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 实时弹幕事件
8 | message DanmukuEvent {
9 | // 弹幕列表
10 | repeated DanmakuElem elems = 1;
11 | }
12 |
13 | // 弹幕条目
14 | message DanmakuElem {
15 | // 弹幕dmid
16 | int64 id = 1;
17 | // 弹幕出现位置(单位为ms)
18 | int32 progress = 2;
19 | // 弹幕类型
20 | int32 mode = 3;
21 | // 弹幕字号
22 | int32 fontsize = 4;
23 | // 弹幕颜色
24 | uint32 color = 5;
25 | // 发送着mid hash
26 | string mid_hash = 6;
27 | // 弹幕正文
28 | string content = 7;
29 | // 发送时间
30 | int64 ctime = 8;
31 | // 弹幕动作
32 | string action = 9;
33 | // 弹幕池
34 | int32 pool = 10;
35 | // 弹幕id str
36 | string id_str = 11;
37 | }
38 |
39 | // 互动弹幕
40 | message CommandDm {
41 | // 弹幕id
42 | int64 id = 1;
43 | // 对象视频cid
44 | int64 oid = 2;
45 | // 发送者mid
46 | int64 mid = 3;
47 | //
48 | int32 type = 4;
49 | // 互动弹幕指令
50 | string command = 5;
51 | // 互动弹幕正文
52 | string content = 6;
53 | // 弹幕状态
54 | int32 state = 7;
55 | // 出现时间
56 | int32 progress = 8;
57 | // 创建时间
58 | string ctime = 9;
59 | // 发布时间
60 | string mtime = 10;
61 | // 扩展json数据
62 | string extra = 11;
63 | // 弹幕id str类型
64 | string idStr = 12;
65 | }
66 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/main/native.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.main;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | //
10 | service NativePage {
11 | //
12 | rpc WatchNotify(google.protobuf.Empty) returns (stream NativePageEvent);
13 | }
14 |
15 | //
16 | message NativePageEvent {
17 | // Native页ID
18 | int64 PageID = 1;
19 | //
20 | repeated EventItem Items = 2;
21 | }
22 |
23 | //
24 | message EventItem {
25 | // 组件标识
26 | int64 ItemID = 1;
27 | // 组件类型
28 | string Type = 2;
29 | // 进度条数值
30 | int64 Num = 3;
31 | // 进度条展示数值
32 | string DisplayNum = 4;
33 | // h5的组件标识
34 | string WebKey = 5;
35 | // 活动统计维度
36 | // 0:用户维度 1:规则维度
37 | int64 dimension = 6;
38 | }
39 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/main/resource.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.main;
4 |
5 | import "google/protobuf/empty.proto";
6 |
7 | option java_multiple_files = true;
8 |
9 | //
10 | service Resource {
11 | //
12 | rpc TopActivity(google.protobuf.Empty) returns (stream TopActivityReply);
13 | }
14 |
15 | //
16 | message TopActivityReply {
17 | // 当前生效的资源
18 | TopOnline online = 1;
19 | // 对online内容进行hash和上次结果一样则不重新加载
20 | string hash = 2;
21 | }
22 |
23 | // 当前生效的资源
24 | message TopOnline {
25 | // 活动类型
26 | // 1:七日活动 2:后台配置
27 | int32 type = 1;
28 | // 图标
29 | string icon = 2;
30 | // 跳转链接
31 | string uri = 3;
32 | // 资源状态标识(后台配置)
33 | string unique_id = 4;
34 | // 动画资源
35 | Animate animate = 5;
36 | // 红点
37 | RedDot red_dot = 6;
38 | // 活动名称
39 | string name = 7;
40 | // 轮询间隔 单位秒
41 | int64 interval = 8;
42 | }
43 |
44 | // 动画资源
45 | message Animate {
46 | // 动效结束展示icon
47 | string icon = 1;
48 | // 7日活动动画
49 | string json = 2;
50 | // s10活动svg动画
51 | string svg = 3;
52 | // 循环次数(默认0不返回 表示无限循环)
53 | int32 loop = 4;
54 | }
55 |
56 | // 红点
57 | message RedDot {
58 | // 红点类型
59 | // 1:纯红点 2:数字红点
60 | int32 type = 1;
61 | // 如果是数字红点 显示的数字
62 | int32 number = 2;
63 | }
64 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/main/search.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.main;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 | import "bilibili/app/dynamic/v2/dynamic.proto";
9 |
10 | service Search {
11 | rpc ChatResultPush (google.protobuf.Empty) returns (stream ChatResult);
12 | }
13 |
14 | //
15 | message Bubble {
16 | repeated bilibili.app.dynamic.v2.Paragraph paragraphs = 1;
17 | }
18 |
19 | //
20 | message ChatResult {
21 | //
22 | int32 code = 1;
23 | //
24 | string session_id = 2;
25 | //
26 | repeated Bubble bubble = 3;
27 | //
28 | string rewrite_word = 4;
29 | //
30 | string title = 5;
31 | }
32 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/note/sync.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.note;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message Sync {
9 | // 笔记id
10 | int64 note_id = 1;
11 | // 唯一标示
12 | string hash = 2;
13 | }
14 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/ogv/live.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.ogv;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 开播事件
8 | message LiveStartEvent {}
9 |
10 | // 直播中止事件
11 | message LiveEndEvent {}
12 |
13 | // 在线人数事件
14 | message LiveOnlineEvent {
15 | //在线人数
16 | int64 online = 1;
17 | }
18 |
19 | // 变更通知
20 | message LiveUpdateEvent {
21 | // 直播后状态
22 | // 1:下线 2:转点播
23 | int32 after_premiere_type = 1;
24 | // 直播开始绝对时间 单位ms
25 | int64 start_time = 2;
26 | // id
27 | string id = 3;
28 | // 服务端播放进度,未打散,负数表示距离开播时间,正数表示已开播时间,单位:毫秒
29 | // 用户实际播放进度:progress - delay_time
30 | int64 progress = 4;
31 | }
32 |
33 | // 直播间事件
34 | message CMDBody {
35 | //命令类型
36 | oneof event {
37 | // 开播事件
38 | LiveStartEvent start = 1;
39 | // 直播中止事件
40 | LiveEndEvent emergency = 2;
41 | // 在线人数事件
42 | LiveOnlineEvent online = 3;
43 | // 变更通知
44 | LiveUpdateEvent update = 4;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/message/ticket/activitygame.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.message.ticket;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | enum RoomStatus {
9 | // 暂停:
10 | Pause = 0;
11 | // 播放:
12 | Play = 1;
13 | // 终止:
14 | End = 2;
15 | }
16 |
17 | // 推送选项
18 | message RoomEvent {
19 | // RoomStatus 类型
20 | RoomStatus room_status = 1;
21 | //
22 | string room_message = 2;
23 | }
24 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/v1/laser.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | // Laser
10 | service Laser {
11 | // 监听上报事件
12 | rpc WatchLogUploadEvent(google.protobuf.Empty) returns (stream LaserLogUploadResp);
13 | }
14 |
15 | // 服务端下发日志上报事件
16 | message LaserLogUploadResp {
17 | // 任务id
18 | int64 taskid = 1;
19 | // 下发时间
20 | string date = 2;
21 | }
22 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/v1/mod.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | // ModManager
10 | service ModManager {
11 | //
12 | rpc WatchResource(google.protobuf.Empty) returns (stream ModResourceResp);
13 | }
14 |
15 | //
16 | message ModResourceResp {
17 | //
18 | int32 atcion = 1;
19 | //
20 | string app_key = 2;
21 | //
22 | string pool_name = 3;
23 | //
24 | string module_name = 4;
25 | //
26 | int64 module_version = 5;
27 | //
28 | int64 list_version = 6;
29 | }
30 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/v1/test.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/any.proto";
8 | import "google/protobuf/empty.proto";
9 |
10 | // 服务端下发的测试专用消息,客户端debug/release包都会通过弹窗响应该消息
11 | // 后端平台 必须 限制该消息只能针对单个用户发送
12 |
13 | // Test
14 | service Test {
15 | // 监听上报事件
16 | rpc WatchTestEvent(google.protobuf.Empty) returns (stream TestResp);
17 | }
18 |
19 | //
20 | service Test2 {
21 | //
22 | rpc Test(AddParams) returns (google.protobuf.Empty);
23 | }
24 |
25 | //
26 | message AddParams {
27 | //
28 | int32 a = 1;
29 | //
30 | int32 b = 2;
31 | }
32 |
33 | //
34 | message AddResult {
35 | //
36 | int32 r = 1;
37 | }
38 |
39 | message TestResp {
40 | // 任务id
41 | int64 taskid = 1;
42 | // 时间戳
43 | int64 timestamp = 2;
44 | // 消息
45 | string message = 3;
46 | // 扩展
47 | google.protobuf.Any extra = 4;
48 | }
49 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/broadcast/v2/laser.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.broadcast.v2;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | // Laser
10 | service Laser {
11 | // 监听Laser事件
12 | rpc WatchEvent(google.protobuf.Empty) returns (stream LaserEventResp);
13 | }
14 |
15 | // 服务端下发Laser事件
16 | message LaserEventResp {
17 | // 任务id
18 | int64 taskid = 1;
19 | // 指令名
20 | string action = 2;
21 | // 指令参数json字符串
22 | string params = 3;
23 | }
24 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/community/service/govern/v1/govern.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.community.service.govern.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/empty.proto";
8 |
9 | //
10 | service Qoe {
11 | //
12 | rpc QoeReport (QoeReportReq) returns (google.protobuf.Empty);
13 | }
14 |
15 | //
16 | message QoeReportReq {
17 | //
18 | int64 id = 1;
19 | //
20 | int64 scene = 2;
21 | //
22 | int32 type = 3;
23 | //
24 | bool cancel = 4;
25 | //
26 | string business_type = 5;
27 | //
28 | int64 oid = 6;
29 | //
30 | QoeScoreResult score_result = 7;
31 | //
32 | string business_data = 8;
33 | }
34 |
35 | //
36 | message QoeScoreResult {
37 | //
38 | float score = 1;
39 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/im/interfaces/inner-interface/v1/api.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.im.interface.inner.interface.v1;
4 |
5 | option java_multiple_files = true;
6 | option java_package = "bilibili.im.interfaces.inner.interface1.v1";
7 |
8 | //
9 | service InnerInterface {
10 | //
11 | rpc UpdateListInn(ReqOpBlacklist) returns(RspOpBlacklist);
12 | }
13 |
14 | //
15 | message BanUser {
16 | // 用户mid
17 | uint64 uid = 1;
18 | // 封禁业务
19 | int32 limit = 2;
20 | // 封禁时间
21 | int32 time = 3;
22 | // 模式
23 | // 1:add 2:remove
24 | int32 mode = 4;
25 | }
26 |
27 | //
28 | message ReqOpBlacklist {
29 | // 需要封禁/解封的用户信息
30 | repeated BanUser ban_users = 1;
31 | }
32 |
33 | //
34 | message RspOpBlacklist {
35 | //
36 | repeated uint64 failed_users = 1;
37 | }
38 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/live/app/room/v1/room.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.live.app.room.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message GetStudioListReq {
9 | //
10 | int64 room_id = 1;
11 | }
12 |
13 | //
14 | message GetStudioListResp {
15 | //
16 | message Pendants {
17 | //
18 | Pendant frame = 1;
19 | //
20 | Pendant badge = 2;
21 | }
22 | //
23 | message Pendant {
24 | //
25 | string name = 1;
26 | //
27 | int64 position = 2;
28 | //
29 | string value = 3;
30 | //
31 | string desc = 4;
32 | }
33 | //
34 | message StudioMaster {
35 | //
36 | int64 uid = 1;
37 | //
38 | int64 room_id = 2;
39 | //
40 | string uname = 3;
41 | //
42 | string face = 4;
43 | //
44 | Pendants pendants = 5;
45 | //
46 | string tag = 6;
47 | //
48 | int64 tag_type = 7;
49 | }
50 | //
51 | int64 status = 1;
52 | //
53 | repeated StudioMaster master_list = 2;
54 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/live/general/interfaces/v1/interfaces.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.live.general.interfaces.v1;
4 |
5 | option java_multiple_files = true;
6 | option java_package = "bilibili.live.general.interfaces.v1";
7 |
8 | //
9 | message GetOnlineRankReq {
10 | //
11 | int64 ruid = 1;
12 | //
13 | int64 room_id = 2;
14 | //
15 | int64 page = 3;
16 | //
17 | int64 page_size = 4;
18 | //
19 | string platform = 5;
20 | }
21 |
22 | //
23 | message GetOnlineRankResp {
24 | //
25 | message OnlineRankItem {
26 | //
27 | int64 uid = 1;
28 | //
29 | string uname = 2;
30 | //
31 | string face = 3;
32 | //
33 | int64 continue_watch = 4;
34 | //
35 | MedalInfo medal_info = 5;
36 | //
37 | int64 guard_level = 6;
38 | }
39 | //
40 | OnlineRankItem item = 1;
41 | //
42 | int64 online_num = 2;
43 | }
44 |
45 | //
46 | message MedalInfo {
47 | //
48 | int64 guard_level = 1;
49 | //
50 | int64 medal_color_start = 2;
51 | //
52 | int64 medal_color_end = 3;
53 | //
54 | int64 medal_color_border = 4;
55 | //
56 | string medal_name = 5;
57 | //
58 | int64 level = 6;
59 | //
60 | int64 target_id = 7;
61 | //
62 | int64 is_light = 8;
63 | }
64 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/main/common/arch/doll/v1/doll.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.main.common.arch.doll.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | service Echo {
9 | //
10 | rpc Ping(PingRequest) returns(PingResponse);
11 | //
12 | rpc Say(SayRequest) returns(SayResponse);
13 | //
14 | rpc Error(ErrorRequest) returns(ErrorResponse);
15 | }
16 |
17 | //
18 | message ErrorRequest {
19 | //
20 | int32 error = 2;
21 | //
22 | int64 time = 1;
23 | //
24 | int64 delay = 3;
25 | }
26 |
27 | //
28 | message ErrorResponse {
29 | //
30 | string host = 1;
31 | //
32 | int64 time = 3;
33 | }
34 |
35 | //
36 | message PingRequest {
37 | //
38 | int64 time = 1;
39 | }
40 |
41 | //
42 | message PingResponse {
43 | //
44 | string host = 1;
45 | //
46 | int64 time = 3;
47 | }
48 |
49 | //
50 | message SayRequest {
51 | //
52 | string content = 1;
53 | }
54 |
55 | //
56 | message SayResponse {
57 | //
58 | string host = 1;
59 | //
60 | string content = 2;
61 | //
62 | int64 time = 3;
63 | }
64 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/device/device.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata.device;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 设备信息
8 | // gRPC头部:x-bili-device-bin
9 | message Device {
10 | // 产品id
11 | // 粉 白 蓝 直播姬 HD 海外 OTT 漫画 TV野版 小视频 网易漫画 网易漫画 网易漫画HD 国际版 东南亚版
12 | // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 30
13 | int32 app_id = 1;
14 | // 构建id
15 | int32 build = 2;
16 | // 设备buvid
17 | string buvid = 3;
18 | // 包类型
19 | string mobi_app = 4;
20 | // 平台类型
21 | // ios android
22 | string platform = 5;
23 | // 设备类型
24 | string device = 6;
25 | // 渠道
26 | string channel = 7;
27 | // 手机品牌
28 | string brand = 8;
29 | // 手机型号
30 | string model = 9;
31 | // 系统版本
32 | string osver = 10;
33 | // 本地设备指纹
34 | string fp_local = 11;
35 | // 远程设备指纹
36 | string fp_remote = 12;
37 | // APP版本号
38 | string version_name = 13;
39 | // 设备指纹, 不区分本地或远程设备指纹,作为推送目标的索引
40 | string fp = 14;
41 | // 首次启动时的毫秒时间戳
42 | int64 fts = 15;
43 | }
44 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/fawkes/fawkes.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata.fawkes;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message FawkesReply {
9 | // 客户端在fawkes系统中对应的已发布最新的config版本号
10 | string config = 1;
11 | // 客户端在fawkes系统中对应的已发布最新的ff版本号
12 | string ff = 2;
13 | }
14 |
15 | //
16 | message FawkesReq {
17 | // 客户端在fawkes系统的唯一名, 如 `android64`
18 | string appkey = 1;
19 | // 客户端在fawkes系统中的环境参数, 如 `prod`
20 | string env = 2;
21 | // 启动id, 8 位 0~9, a~z 组成的字符串
22 | string session_id = 3;
23 | }
24 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/locale/locale.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata.locale;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 区域标识
8 | // gRPC头部:x-bili-locale-bin
9 | message Locale {
10 | // App设置的locale
11 | LocaleIds c_locale = 1;
12 | // 系统默认的locale
13 | LocaleIds s_locale = 2;
14 | // sim卡的国家码+运营商码
15 | string sim_code = 3;
16 | // 时区
17 | string timezone = 4;
18 | }
19 |
20 | // Defined by https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html
21 | message LocaleIds {
22 | // A language designator is a code that represents a language.
23 | string language = 1;
24 | // Writing systems.
25 | string script = 2;
26 | // A region designator is a code that represents a country or an area.
27 | string region = 3;
28 | }
29 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/metadata.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 请求元数据
8 | // gRPC头部:x-bili-metadata-bin
9 | message Metadata {
10 | // 登录 access_key
11 | string access_key = 1;
12 | // 包类型, 如 `android`
13 | string mobi_app = 2;
14 | // 运行设备, 留空即可
15 | string device = 3;
16 | // 构建id, 如 `7380300`
17 | int32 build = 4;
18 | // APP分发渠道, 如 `master`
19 | string channel = 5;
20 | // 设备唯一标识
21 | string buvid = 6;
22 | // 平台类型, 如 `android`
23 | string platform = 7;
24 | }
25 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/network/network.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata.network;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 网络类型标识
8 | // gRPC头部:x-bili-network-bin
9 | message Network {
10 | // 网络类型
11 | NetworkType type = 1;
12 | // 免流类型
13 | TFType tf = 2;
14 | // 运营商
15 | string oid = 3;
16 | }
17 |
18 | // 网络类型
19 | enum NetworkType {
20 | NT_UNKNOWN = 0; // 未知
21 | WIFI = 1; // WIFI
22 | CELLULAR = 2; // 蜂窝网络
23 | OFFLINE = 3; // 未连接
24 | OTHERNET = 4; // 其他网络
25 | ETHERNET = 5; // 以太网
26 | }
27 |
28 | // 免流类型
29 | enum TFType {
30 | TF_UNKNOWN = 0; // 正常计费
31 | U_CARD = 1; // 联通卡
32 | U_PKG = 2; // 联通包
33 | C_CARD = 3; // 移动卡
34 | C_PKG = 4; // 移动包
35 | T_CARD = 5; // 电信卡
36 | T_PKG = 6; // 电信包
37 | }
38 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/parabox/parabox.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata.parabox;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message Exp {
9 | //
10 | int64 id = 1;
11 | //
12 | int32 bucket = 2;
13 | }
14 |
15 | //
16 | message Exps {
17 | //
18 | repeated Exp exps = 1;
19 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/metadata/restriction/restriction.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.metadata.restriction;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 模式类型
8 | enum ModeType {
9 | NORMAL = 0; // 正常模式
10 | TEENAGERS = 1; // 青少年模式
11 | LESSONS = 2; // 课堂模式
12 | }
13 |
14 | // 限制条件
15 | message Restriction {
16 | // 青少年模式开关状态
17 | bool teenagers_mode = 1;
18 | // 课堂模式开关状态
19 | bool lessons_mode = 2;
20 | // 模式类型(旧版)
21 | ModeType mode = 3;
22 | // app 审核review状态
23 | bool review = 4;
24 | // 客户端是否选择关闭个性化推荐
25 | bool disable_rcmd = 5;
26 | }
27 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/pagination/pagination.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.pagination;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 分页信息
8 | message FeedPagination {
9 | //
10 | int32 page_size = 1;
11 | //
12 | string offset = 2;
13 | //
14 | bool is_refresh = 3;
15 | }
16 |
17 | // 分页信息
18 | message FeedPaginationReply {
19 | //
20 | string next_offset = 1;
21 | //
22 | string prev_offset = 2;
23 | //
24 | string last_read_offset = 3;
25 | }
26 |
27 | // 分页信息
28 | message Pagination {
29 | //
30 | int32 page_size = 1;
31 | //
32 | string next = 2;
33 | }
34 |
35 | // 分页信息
36 | message PaginationReply {
37 | //
38 | string next = 1;
39 | //
40 | string prev = 2;
41 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/pgc/service/premiere/v1/premiere.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.pgc.service.premiere.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | // 首播服务
8 | service Premiere {
9 | // 获取首播状态
10 | rpc Status (PremiereStatusReq) returns (PremiereStatusReply);
11 | }
12 |
13 | // 获取首播状态-请求
14 | message PremiereStatusReq {
15 | // 剧集epid
16 | int64 ep_id = 1;
17 | }
18 |
19 | // 获取首播状态-响应
20 | message PremiereStatusReply {
21 | // 服务端播放进度 单位ms 用户实际播放进度:progress - delay_time
22 | int64 progress = 1;
23 | // 起播时间戳 单位ms
24 | int64 start_time = 2;
25 | // 延迟播放时长 单位ms
26 | int64 delay_time = 3;
27 | // 首播在线人数
28 | int64 online_count = 4;
29 | // 首播状态
30 | // 1:预热 2:首播中 3:紧急停播 4:已结束
31 | int32 status = 5;
32 | // 首播结束后跳转类型
33 | // 1:下架 2:转点播
34 | int32 after_premiere_type = 6;
35 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/polymer/demo/demo.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.polymer.demo;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message HelloWorldReq {
9 | //
10 | string content = 1;
11 | }
12 |
13 | //
14 | message HelloWorldResp {
15 | //
16 | string data = 1;
17 | }
18 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/polymer/list/v1/list.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.polymer.list.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | service List {
9 | //
10 | rpc FavoriteTab(FavoriteTabReq) returns (FavoriteTabReply);
11 | //
12 | rpc CheckAccount(CheckAccountReq) returns (CheckAccountReply);
13 | }
14 |
15 | //
16 | message CheckAccountReply {
17 | //
18 | bool is_new = 1;
19 | }
20 |
21 | //
22 | message CheckAccountReq {
23 | //
24 | int64 uid = 1;
25 | //
26 | string periods = 2;
27 | }
28 |
29 | //
30 | message FavoriteTabItem {
31 | //
32 | string name = 1;
33 | //
34 | string uri = 2;
35 | //
36 | string type = 3;
37 | }
38 |
39 | //
40 | message FavoriteTabReply {
41 | //
42 | repeated FavoriteTabItem items = 1;
43 | }
44 |
45 | //
46 | message FavoriteTabReq {}
47 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/relation/interfaces/api.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.relation.interface.v1;
4 |
5 | option java_multiple_files = true;
6 | option java_package = "bilibili.relation.interface1.v1";
7 |
8 | service RelationInterface {
9 | // 评论区 At 用户列表 (无需登录鉴权)
10 | rpc AtSearch (AtSearchReq) returns (AtSearchReply);
11 | }
12 |
13 | message AtSearchReq {
14 | // 可以为 1 , 但是不能为 0 或空 不知道有啥用
15 | int64 mid = 1;
16 | // 用户名搜索关键词
17 | string keyword = 2;
18 | }
19 |
20 | message AtSearchReply {
21 | // 搜索结果分组
22 | repeated AtGroup items = 1;
23 | }
24 |
25 | message AtGroup {
26 | // 分组类型 2: 我的关注 4:其他 ,其他自测
27 | int32 group_type = 1;
28 | // 分组名称
29 | string group_name = 2;
30 | // 用户列表
31 | repeated AtItem items = 3;
32 | }
33 |
34 | message AtItem {
35 | int64 mid = 1;
36 | string name = 2;
37 | string face = 3;
38 | int32 fans = 4;
39 | int32 official_verify_type = 5;
40 | }
41 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/render/render.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.render;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/any.proto";
8 |
9 | //
10 | message Render {
11 | //
12 | int64 code = 1;
13 | //
14 | string message = 2;
15 | //
16 | string ttl = 3;
17 | //
18 | google.protobuf.Any data = 4;
19 | }
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/rpc/status.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.rpc;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/any.proto";
8 |
9 | // 响应gRPC Status
10 | // 当status code是[UNKNOWN = 2]时,details为业务详细的错误信息,进行proto any转换成业务码结构体
11 | message Status {
12 | // 业务错误码
13 | int32 code = 1;
14 | // 业务错误信息
15 | string message = 2;
16 | // 扩展信息嵌套(相当于该messasge的套娃)
17 | repeated google.protobuf.Any details = 3;
18 | }
19 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/bilibili/vega/deneb/v1/deneb.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package bilibili.vega.deneb.v1;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/any.proto";
8 |
9 | //
10 | service VegaDenebRPC {
11 | //
12 | rpc MessagePulls (MessagePullsReq) returns (MessagePullsReply);
13 | }
14 |
15 | //
16 | message MessagePullsReply {
17 | //
18 | repeated google.protobuf.Any data = 1;
19 | //
20 | int32 pn = 2;
21 | //
22 | int32 ps = 3;
23 | //
24 | int64 count = 4;
25 | //
26 | bool has_next = 5;
27 | }
28 |
29 | //
30 | message MessagePullsReq {
31 | //
32 | int64 start_seq_id = 1;
33 | //
34 | int64 end_seq_id = 2;
35 | //
36 | int32 pn = 3;
37 | //
38 | int32 ps = 4;
39 | }
40 |
41 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/common/ErrorProto.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package common;
4 |
5 | option java_multiple_files = true;
6 |
7 | import "google/protobuf/any.proto";
8 |
9 | // 响应gRPC Status
10 | // 当status code是[UNKNOWN = 2]时,details为业务详细的错误信息,进行proto any转换成业务码结构体
11 | message ErrorProto {
12 | // 业务错误码
13 | int32 code = 1;
14 | // 业务错误信息
15 | string message = 2;
16 | // 扩展信息嵌套(相当于该messasge的套娃)
17 | repeated google.protobuf.Any details = 3;
18 | }
19 |
--------------------------------------------------------------------------------
/bili-api-grpc/proto/pgc/biz/room.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package pgc.biz;
4 |
5 | option java_multiple_files = true;
6 |
7 | //
8 | message RoomProto {
9 | //
10 | repeated string room_id = 1;
11 | }
--------------------------------------------------------------------------------
/bili-api/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/bili-api/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(gradleLibs.plugins.kotlin.jvm)
3 | alias(gradleLibs.plugins.kotlin.serialization)
4 | }
5 |
6 | group = "dev.aaa1115910"
7 |
8 | dependencies {
9 | implementation(project(":bili-api-grpc"))
10 | implementation(libs.jsoup)
11 | implementation(libs.kotlinx.coroutines)
12 | implementation(libs.kotlinx.serialization)
13 | implementation(libs.ktor.client.content.negotiation)
14 | implementation(libs.ktor.client.core)
15 | implementation(libs.ktor.client.encoding)
16 | //implementation(libs.ktor.jsoup)
17 | implementation(libs.ktor.client.okhttp)
18 | implementation(libs.ktor.client.serialization.kotlinx)
19 | implementation(libs.logging)
20 | implementation(libs.slf4j.simple)
21 | testImplementation(libs.kotlin.test)
22 | }
23 |
24 | tasks.test {
25 | useJUnitPlatform()
26 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/COMBO_SEND.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "COMBO_SEND",
3 | "data": {
4 | "action": "投喂",
5 | "batch_combo_id": "batch:gift:combo_id:21486712:168598:31036:1669433933.0434",
6 | "batch_combo_num": 2,
7 | "combo_id": "gift:combo_id:21486712:168598:31036:1669433933.0427",
8 | "combo_num": 2,
9 | "combo_total_coin": 200,
10 | "dmscore": 56,
11 | "gift_id": 31036,
12 | "gift_name": "小花花",
13 | "gift_num": 0,
14 | "is_naming": false,
15 | "is_show": 1,
16 | "medal_info": {
17 | "anchor_roomid": 0,
18 | "anchor_uname": "",
19 | "guard_level": 0,
20 | "icon_id": 0,
21 | "is_lighted": 1,
22 | "medal_color": 9272486,
23 | "medal_color_border": 9272486,
24 | "medal_color_end": 9272486,
25 | "medal_color_start": 9272486,
26 | "medal_level": 11,
27 | "medal_name": "刺儿",
28 | "special": "",
29 | "target_id": 168598
30 | },
31 | "name_color": "",
32 | "r_uname": "逍遥散人",
33 | "ruid": 168598,
34 | "send_master": null,
35 | "total_num": 2,
36 | "uid": 21486712,
37 | "uname": "Ms星鸢"
38 | }
39 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/ENTRY_EFFECT.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "ENTRY_EFFECT",
3 | "data": {
4 | "id": 4,
5 | "uid": 12342661,
6 | "target_id": 8739477,
7 | "mock_effect": 0,
8 | "face": "https://i1.hdslb.com/bfs/face/3d876e4fb959d0089e3c0299afae9fead128c70a.jpg",
9 | "privilege_type": 3,
10 | "copy_writing": "欢迎舰长 <%整点薯条吃吃吃%> 进入直播间",
11 | "copy_color": "#ffffff",
12 | "highlight_color": "#E6FF00",
13 | "priority": 1,
14 | "basemap_url": "https://i0.hdslb.com/bfs/live/mlive/11a6e8eb061c3e715d0a6a2ac0ddea2faa15c15e.png",
15 | "show_avatar": 1,
16 | "effective_time": 2,
17 | "web_basemap_url": "https://i0.hdslb.com/bfs/live/mlive/11a6e8eb061c3e715d0a6a2ac0ddea2faa15c15e.png",
18 | "web_effective_time": 2,
19 | "web_effect_close": 0,
20 | "web_close_time": 0,
21 | "business": 1,
22 | "copy_writing_v2": "欢迎舰长 <%整点薯条吃吃吃%> 进入直播间",
23 | "icon_list": [],
24 | "max_delay_time": 7,
25 | "trigger_time": 1669400294516525185,
26 | "identities": 6,
27 | "effect_silent_time": 0,
28 | "effective_time_new": 0,
29 | "web_dynamic_url_webp": "",
30 | "web_dynamic_url_apng": "",
31 | "mobile_dynamic_url_webp": ""
32 | }
33 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/GUARD_BUY.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "GUARD_BUY",
3 | "data": {
4 | "uid": 6501027,
5 | "username": "玉紫",
6 | "guard_level": 3,
7 | "num": 1,
8 | "price": 198000,
9 | "gift_id": 10003,
10 | "gift_name": "舰长",
11 | "start_time": 1669435051,
12 | "end_time": 1669435051
13 | }
14 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/HOT_RANK_SETTLEMENT.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "HOT_RANK_SETTLEMENT",
3 | "data": {
4 | "area_name": "手游",
5 | "cache_key": "c2f8a79cc9a709237fb65df23fd61025",
6 | "dm_msg": "恭喜主播 <% 逍遥散人 %> 荣登限时热门榜手游榜top9! 即将获得轮播资源位推荐哦!",
7 | "dmscore": 144,
8 | "face": "https://i1.hdslb.com/bfs/face/8a5de2d7486251e80307d8600cbf8649eb4035fe.jpg",
9 | "icon": "https://i0.hdslb.com/bfs/live/b4961bcfba56a26b69c35690dfcbdabbeb973c64.png",
10 | "rank": 9,
11 | "timestamp": 1669435204,
12 | "uname": "逍遥散人",
13 | "url": "https://live.bilibili.com/p/html/live-app-hotrank/result.html?is_live_half_webview=1&hybrid_half_ui=1,5,250,200,f4eefa,0,30,0,0,0;2,5,250,200,f4eefa,0,30,0,0,0;3,5,250,200,f4eefa,0,30,0,0,0;4,5,250,200,f4eefa,0,30,0,0,0;5,5,250,200,f4eefa,0,30,0,0,0;6,5,250,200,f4eefa,0,30,0,0,0;7,5,250,200,f4eefa,0,30,0,0,0;8,5,250,200,f4eefa,0,30,0,0,0&areaId=3&cache_key=c2f8a79cc9a709237fb65df23fd61025"
14 | }
15 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/HOT_RANK_SETTLEMENT_V2.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "HOT_RANK_SETTLEMENT_V2",
3 | "data": {
4 | "rank": 7,
5 | "uname": "逍遥散人",
6 | "face": "https://i1.hdslb.com/bfs/face/8a5de2d7486251e80307d8600cbf8649eb4035fe.jpg",
7 | "timestamp": 1669434904,
8 | "icon": "https://i0.hdslb.com/bfs/live/cb2e160ac4f562b347bb5ae6e635688ebc69580f.png",
9 | "area_name": "原神",
10 | "url": "https://live.bilibili.com/p/html/live-app-hotrank/result.html?is_live_half_webview=1&hybrid_half_ui=1,5,250,200,f4eefa,0,30,0,0,0;2,5,250,200,f4eefa,0,30,0,0,0;3,5,250,200,f4eefa,0,30,0,0,0;4,5,250,200,f4eefa,0,30,0,0,0;5,5,250,200,f4eefa,0,30,0,0,0;6,5,250,200,f4eefa,0,30,0,0,0;7,5,250,200,f4eefa,0,30,0,0,0;8,5,250,200,f4eefa,0,30,0,0,0&areaId=321&cache_key=17276a47cc6fd1420feb0f2d86f60e85",
11 | "cache_key": "17276a47cc6fd1420feb0f2d86f60e85",
12 | "dm_msg": "恭喜主播 <% 逍遥散人 %> 荣登限时热门榜原神榜top7! 即将获得轮播资源位推荐哦!"
13 | }
14 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/HOT_ROOM_NOTIFY.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "HOT_ROOM_NOTIFY",
3 | "data": {
4 | "threshold": 10000,
5 | "ttl": 300,
6 | "exit_no_refresh": 1,
7 | "random_delay_req_v2": [
8 | {
9 | "path": "/live/getRoundPlayVideo",
10 | "delay": 10
11 | },
12 | {
13 | "path": "/xlive/web-room/v1/index/getOffLiveList",
14 | "delay": 120000
15 | }
16 | ]
17 | }
18 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/INTERACT_WORD.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "INTERACT_WORD",
3 | "data": {
4 | "contribution": {
5 | "grade": 0
6 | },
7 | "dmscore": 2,
8 | "fans_medal": {
9 | "anchor_roomid": 0,
10 | "guard_level": 0,
11 | "icon_id": 0,
12 | "is_lighted": 0,
13 | "medal_color": 0,
14 | "medal_color_border": 0,
15 | "medal_color_end": 0,
16 | "medal_color_start": 0,
17 | "medal_level": 0,
18 | "medal_name": "",
19 | "score": 0,
20 | "special": "",
21 | "target_id": 0
22 | },
23 | "identities": [
24 | 1
25 | ],
26 | "is_spread": 0,
27 | "msg_type": 1,
28 | "privilege_type": 0,
29 | "roomid": 21721813,
30 | "score": 1669399871533,
31 | "spread_desc": "",
32 | "spread_info": "",
33 | "tail_icon": 0,
34 | "timestamp": 1669399871,
35 | "trigger_time": 1669399870422980000,
36 | "uid": 268831673,
37 | "uname": "丸子泡汤ON",
38 | "uname_color": ""
39 | }
40 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/LIKE_INFO_V3_CLICK.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "LIKE_INFO_V3_CLICK",
3 | "data": {
4 | "show_area": 0,
5 | "msg_type": 6,
6 | "like_icon": "https://i0.hdslb.com/bfs/live/23678e3d90402bea6a65251b3e728044c21b1f0f.png",
7 | "uid": 393552291,
8 | "like_text": "为主播点赞了",
9 | "uname": "有卢克迪丽歇斯",
10 | "uname_color": "",
11 | "identities": [
12 | 1
13 | ],
14 | "fans_medal": {
15 | "target_id": 0,
16 | "medal_level": 0,
17 | "medal_name": "",
18 | "medal_color": 0,
19 | "medal_color_start": 12632256,
20 | "medal_color_end": 12632256,
21 | "medal_color_border": 12632256,
22 | "is_lighted": 0,
23 | "guard_level": 0,
24 | "special": "",
25 | "icon_id": 0,
26 | "anchor_roomid": 0,
27 | "score": 0
28 | },
29 | "contribution_info": {
30 | "grade": 0
31 | },
32 | "dmscore": 20
33 | }
34 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/LIKE_INFO_V3_UPDATE.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "LIKE_INFO_V3_UPDATE",
3 | "data": {
4 | "click_count": 15805
5 | }
6 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/LIVE_INTERACTIVE_GAME.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "LIVE_INTERACTIVE_GAME",
3 | "data": {
4 | "type": 2,
5 | "uid": 2588066,
6 | "uname": "傻傻分不清噜",
7 | "uface": "",
8 | "gift_id": 0,
9 | "gift_name": "",
10 | "gift_num": 0,
11 | "price": 0,
12 | "paid": false,
13 | "msg": "这个debuff还行不影响",
14 | "fans_medal_level": 0,
15 | "guard_level": 0,
16 | "timestamp": 1669400655,
17 | "anchor_lottery": null,
18 | "pk_info": null,
19 | "anchor_info": null,
20 | "combo_info": null
21 | }
22 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/LIVE_MULTI_VIEW_CHANGE.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "LIVE_MULTI_VIEW_CHANGE",
3 | "data": {
4 | "scatter": {
5 | "max": 120,
6 | "min": 5
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/ONLINE_RANK_COUNT.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "ONLINE_RANK_COUNT",
3 | "data": {
4 | "count": 530
5 | }
6 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/ONLINE_RANK_TOP3.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "ONLINE_RANK_TOP3",
3 | "data": {
4 | "dmscore": 112,
5 | "list": [
6 | {
7 | "msg": "恭喜 <%玉紫%> 成为高能用户",
8 | "rank": 2
9 | }
10 | ]
11 | }
12 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/PREPARING.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "PREPARING",
3 | "round": 1,
4 | "roomid": "47867"
5 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/ROOM_REAL_TIME_MESSAGE_UPDATE.json:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "ROOM_REAL_TIME_MESSAGE_UPDATE",
3 | "data": {
4 | "roomid": 545068,
5 | "fans": 2567341,
6 | "red_notice": -1,
7 | "fans_club": 47278
8 | }
9 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/SUPER_CHAT_ENTRANCE.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "SUPER_CHAT_ENTRANCE",
3 | "data": {
4 | "icon": "https://i0.hdslb.com/bfs/live/0a9ebd72c76e9cbede9547386dd453475d4af6fe.png",
5 | "jump_url": "https://live.bilibili.com/p/html/live-app-superchat2/index.html?is_live_half_webview=1&hybrid_half_ui=1,3,100p,70p,ffffff,0,30,100;2,2,375,100p,ffffff,0,30,100;3,3,100p,70p,ffffff,0,30,100;4,2,375,100p,ffffff,0,30,100;5,3,100p,60p,ffffff,0,30,100;6,3,100p,60p,ffffff,0,30,100;7,3,100p,60p,ffffff,0,30,100",
6 | "status": 0
7 | }
8 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/USER_TOAST_MSG.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "USER_TOAST_MSG",
3 | "data": {
4 | "anchor_show": true,
5 | "color": "#00D1F1",
6 | "dmscore": 90,
7 | "effect_id": 397,
8 | "end_time": 1669435051,
9 | "face_effect_id": 44,
10 | "gift_id": 10003,
11 | "guard_level": 3,
12 | "is_show": 0,
13 | "num": 1,
14 | "op_type": 3,
15 | "payflow_id": "2211261157000842110278874",
16 | "price": 138000,
17 | "role_name": "舰长",
18 | "room_effect_id": 590,
19 | "start_time": 1669435051,
20 | "svga_block": 0,
21 | "target_guard_count": 972,
22 | "toast_msg": "<%玉紫%> 续费了舰长,今天是TA陪伴主播的第691天",
23 | "uid": 6501027,
24 | "unit": "月",
25 | "user_show": true,
26 | "username": "玉紫"
27 | }
28 | }
--------------------------------------------------------------------------------
/bili-api/example-response/live-event/WATCHED_CHANGE.json5:
--------------------------------------------------------------------------------
1 | {
2 | "cmd": "WATCHED_CHANGE",
3 | "data": {
4 | "num": 305504,
5 | "text_small": "30.5万",
6 | "text_large": "30.5万人看过"
7 | }
8 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/ApiType.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity
2 |
3 | enum class ApiType {
4 | Web, App
5 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/CodeType.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity
2 |
3 | import bilibili.pgc.gateway.player.v2.CodeType as PgcPlayUrlCodeType
4 | import bilibili.playershared.CodeType as PlayerSharedCodeType
5 |
6 | enum class CodeType(val str: String, val codecId: Int) {
7 | NoCode("none", 0),
8 | Code264("avc1", 7),
9 | Code265("hev1", 12),
10 | CodeAv1("av01", 13),
11 | Unrecognized("unknown", 0);
12 |
13 | companion object{
14 | fun fromCodecId(code: Int?) = runCatching {
15 | entries.find { it.codecId == code }!!
16 | }.getOrDefault(NoCode)
17 | }
18 |
19 | fun toPlayerSharedCodeType() = when (this) {
20 | NoCode -> PlayerSharedCodeType.NOCODE
21 | Code264 -> PlayerSharedCodeType.CODE264
22 | Code265 -> PlayerSharedCodeType.CODE265
23 | CodeAv1 -> PlayerSharedCodeType.CODEAV1
24 | Unrecognized -> PlayerSharedCodeType.UNRECOGNIZED
25 | }
26 |
27 | fun toPgcPlayUrlCodeType() = when (this) {
28 | NoCode, CodeAv1 -> PgcPlayUrlCodeType.NOCODE
29 | Code264 -> PgcPlayUrlCodeType.CODE264
30 | Code265 -> PgcPlayUrlCodeType.CODE265
31 | Unrecognized -> PgcPlayUrlCodeType.UNRECOGNIZED
32 | }
33 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/home/RecommendData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.home
2 |
3 | import dev.aaa1115910.biliapi.entity.ugc.UgcItem
4 |
5 | data class RecommendData(
6 | val items: List,
7 | val nextPage: RecommendPage
8 | )
9 |
10 | data class RecommendPage(
11 | val nextWebIdx: Int = 1,
12 | val nextAppIdx: Int = 0
13 | )
14 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/login/Captcha.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.login
2 |
3 | /**
4 | * 人机数据
5 | *
6 | * @param token 登录 API token
7 | * @param gt 极验id 一般为固定值
8 | * @param challenge 极验KEY 由B站后端产生用于人机验证
9 | */
10 | data class Captcha(
11 | val token: String,
12 | val challenge: String,
13 | val gt: String
14 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/login/QR.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.login
2 |
3 | import java.util.Date
4 |
5 | /**
6 | * 获取扫码登录的二维码
7 | *
8 | * @param url 二维码内容
9 | * @param key 用于查询扫码登录结果
10 | */
11 | data class QrLoginData(
12 | val url: String,
13 | val key: String
14 | )
15 |
16 | /**
17 | * 扫码登录结果
18 | *
19 | * @param state 登录结果状态
20 | * @param cookies 登录成功的 cookies
21 | */
22 | data class QrLoginResult(
23 | val state: QrLoginState,
24 | val accessToken: String? = null,
25 | val refreshToken: String? = null,
26 | val cookies: WebCookies? = null
27 | )
28 |
29 | enum class QrLoginState {
30 | Ready,
31 | RequestingQRCode,
32 | WaitingForScan,
33 | WaitingForConfirm,
34 | Expired,
35 | Success,
36 | Error,
37 | Unknown
38 | }
39 |
40 | data class WebCookies(
41 | val dedeUserId: Long,
42 | val dedeUserIdCkMd5: String,
43 | val sid: String,
44 | val biliJct: String,
45 | val sessData: String,
46 | val expiredDate: Date
47 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/pgc/PgcType.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.pgc
2 |
3 | enum class PgcType {
4 | Anime,
5 | GuoChuang,
6 | Movie,
7 | Documentary,
8 | Tv,
9 | Variety
10 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/pgc/index/PgcIndexData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.pgc.index
2 |
3 | import dev.aaa1115910.biliapi.entity.pgc.PgcItem
4 |
5 | data class PgcIndexData(
6 | val list: List,
7 | val nextPage: PgcIndexPage
8 | ) {
9 | companion object {
10 | fun fromIndexResultData(data: dev.aaa1115910.biliapi.http.entity.index.IndexResultData): PgcIndexData {
11 | return PgcIndexData(
12 | list = data.list.map { PgcItem.fromIndexResultItem(it) },
13 | nextPage = PgcIndexPage(
14 | currentPage = data.num,
15 | pageSize = data.size,
16 | totalSize = data.total,
17 | nextPage = data.num + 1,
18 | hasNext = data.hasNext == 1
19 | )
20 | )
21 | }
22 | }
23 |
24 | data class PgcIndexPage(
25 | val currentPage: Int = 1,
26 | val pageSize: Int = 20,
27 | val totalSize: Int = 0,
28 | val nextPage: Int = 1,
29 | val hasNext: Boolean = true
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/rank/Popular.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.rank
2 |
3 | import dev.aaa1115910.biliapi.entity.ugc.UgcItem
4 |
5 | data class PopularVideoData(
6 | val list: List,
7 | val nextPage: PopularVideoPage,
8 | val noMore: Boolean
9 | )
10 |
11 | data class PopularVideoPage(
12 | val nextWebPageSize: Int = 20,
13 | val nextWebPageNumber: Int = 1,
14 | val nextAppIndex: Int = 0,
15 | )
16 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/search/Hotword.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.search
2 |
3 |
4 | data class Hotword(
5 | val keyword: String,
6 | val showName: String,
7 | val icon: String?,
8 | ) {
9 | companion object {
10 | fun fromHttpWebHotword(hotword: dev.aaa1115910.biliapi.http.entity.search.Hotword) =
11 | Hotword(
12 | keyword = hotword.keyword,
13 | showName = hotword.showName,
14 | icon = hotword.icon
15 | )
16 |
17 | fun fromHttpAppSquareDataItem(squareDataItem: dev.aaa1115910.biliapi.http.entity.search.AppSearchSquareData.SquareData.SquareDataItem) =
18 | Hotword(
19 | keyword = squareDataItem.keyword ?: "",
20 | showName = squareDataItem.showName ?: "",
21 | icon = squareDataItem.icon
22 | )
23 |
24 | fun fromHttpAppSearchTrendingHotword(hotword: dev.aaa1115910.biliapi.http.entity.search.SearchTendingData.Hotword) =
25 | Hotword(
26 | keyword = hotword.keyword,
27 | showName = hotword.showName,
28 | icon = hotword.icon
29 | )
30 | }
31 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/season/FollowingSeasons.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.season
2 |
3 | data class FollowingSeasonData(
4 | val list: List,
5 | val total: Int
6 | )
7 |
8 | data class FollowingSeason(
9 | val seasonId: Int,
10 | val title: String,
11 | val cover: String
12 | ) {
13 | companion object {
14 | fun fromFollowingSeason(season: dev.aaa1115910.biliapi.http.entity.season.WebFollowingSeason) =
15 | FollowingSeason(
16 | seasonId = season.seasonId,
17 | title = season.title,
18 | cover = season.cover
19 | )
20 |
21 | fun fromFollowingSeason(season: dev.aaa1115910.biliapi.http.entity.season.AppFollowingSeason) =
22 | FollowingSeason(
23 | seasonId = season.seasonId,
24 | title = season.title,
25 | cover = season.cover
26 | )
27 | }
28 | }
29 |
30 | enum class FollowingSeasonType(val id: Int, val paramName: String) {
31 | Bangumi(id = 1, paramName = "bangumi"),
32 | Cinema(id = 2, paramName = "cinema")
33 | }
34 |
35 | enum class FollowingSeasonStatus(val id: Int) {
36 | All(id = 0), Want(id = 1), Watching(id = 2), Watched(id = 3)
37 | }
38 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/ugc/region/UgcRegionData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.ugc.region
2 |
3 | import dev.aaa1115910.biliapi.entity.CarouselData
4 | import dev.aaa1115910.biliapi.entity.ugc.UgcItem
5 |
6 | data class UgcRegionData(
7 | val carouselData: CarouselData?,
8 | val items: List,
9 | val next: UgcRegionPage
10 | ) {
11 | companion object {
12 | fun fromRegionDynamic(data: dev.aaa1115910.biliapi.http.entity.region.RegionDynamic): UgcRegionData {
13 | return UgcRegionData(
14 | carouselData = data.banner?.let { CarouselData.fromUgcRegionDynamicBanner(it) },
15 | items = data.new.map { UgcItem.fromRegionDynamicListItem(it) },
16 | next = UgcRegionPage(data.cBottom)
17 | )
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/ugc/region/UgcRegionListData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.ugc.region
2 |
3 | import dev.aaa1115910.biliapi.entity.ugc.UgcItem
4 |
5 | data class UgcRegionListData(
6 | val items: List,
7 | val next: UgcRegionPage
8 | ) {
9 | companion object {
10 | fun fromRegionDynamicList(data: dev.aaa1115910.biliapi.http.entity.region.RegionDynamicList): UgcRegionListData {
11 | return UgcRegionListData(
12 | items = data.new.map { UgcItem.fromRegionDynamicListItem(it) },
13 | next = UgcRegionPage(data.cBottom)
14 | )
15 | }
16 | }
17 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/ugc/region/UgcRegionPage.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.ugc.region
2 |
3 | data class UgcRegionPage(
4 | val nextPage: Long = 0
5 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/user/Author.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.user
2 |
3 | import dev.aaa1115910.biliapi.http.entity.video.VideoOwner
4 |
5 | data class Author(
6 | val mid: Long,
7 | val name: String,
8 | val face: String
9 | ) {
10 | companion object {
11 | fun fromVideoOwner(videoOwner: VideoOwner) = Author(
12 | mid = videoOwner.mid,
13 | name = videoOwner.name,
14 | face = videoOwner.face
15 | )
16 |
17 | fun fromAuthor(author: bilibili.app.archive.v1.Author) = Author(
18 | mid = author.mid,
19 | name = author.name,
20 | face = author.face
21 | )
22 | }
23 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/user/FollowedUser.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.user
2 |
3 | data class FollowedUser(
4 | val mid: Long,
5 | val name: String,
6 | val avatar: String,
7 | val sign: String
8 | ) {
9 | companion object {
10 | fun fromHttpFollowedUser(followedUser: dev.aaa1115910.biliapi.http.entity.user.UserFollowData.FollowedUser) =
11 | FollowedUser(
12 | mid = followedUser.mid,
13 | name = followedUser.uname,
14 | avatar = followedUser.face,
15 | sign = followedUser.sign
16 | )
17 | }
18 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/video/Dimension.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.video
2 |
3 | data class Dimension(
4 | val width: Int,
5 | val height: Int,
6 | val isVertical: Boolean = width < height
7 | ) {
8 | companion object {
9 | fun fromDimension(dimension: bilibili.app.archive.v1.Dimension) = Dimension(
10 | width = dimension.width.toInt(),
11 | height = dimension.height.toInt()
12 | )
13 |
14 | fun fromDimension(dimension: dev.aaa1115910.biliapi.http.entity.video.Dimension) =
15 | Dimension(
16 | width = dimension.width,
17 | height = dimension.height
18 | )
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/video/Heartbeat.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.video
2 |
3 | enum class HeartbeatVideoType(val value: Int) {
4 | Video(3), Season(4), Course(10)
5 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/video/Tag.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.video
2 |
3 | data class Tag(
4 | val id: Int,
5 | val name: String
6 | ) {
7 | companion object {
8 | fun fromTag(tag: dev.aaa1115910.biliapi.http.entity.video.Tag) = Tag(
9 | id = tag.tagId,
10 | name = tag.tagName
11 | )
12 |
13 | fun fromTag(tag: bilibili.app.view.v1.Tag) = Tag(
14 | id = tag.id.toInt(),
15 | name = tag.name
16 | )
17 |
18 | fun fromTag(tag: dev.aaa1115910.biliapi.http.entity.video.VideoDetail.Tag) = Tag(
19 | id = tag.tagId,
20 | name = tag.tagName
21 | )
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/video/VideoPage.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.video
2 |
3 | import bilibili.app.view.v1.ViewPage
4 |
5 | data class VideoPage(
6 | var cid: Long,
7 | val index: Int,
8 | val title: String,
9 | val duration: Int,
10 | val dimension: Dimension
11 | ) {
12 | companion object {
13 | fun fromViewPage(viewPage: ViewPage) = VideoPage(
14 | cid = viewPage.page.cid,
15 | index = viewPage.page.page,
16 | title = viewPage.page.part,
17 | duration = viewPage.page.duration.toInt(),
18 | dimension = Dimension.fromDimension(viewPage.page.dimension)
19 | )
20 |
21 | fun fromVideoPage(videoPage: dev.aaa1115910.biliapi.http.entity.video.VideoPage) =
22 | VideoPage(
23 | cid = videoPage.cid,
24 | index = videoPage.page,
25 | title = videoPage.part,
26 | duration = videoPage.duration,
27 | dimension = Dimension.fromDimension(videoPage.dimension)
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/entity/video/season/Section.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.entity.video.season
2 |
3 | data class Section(
4 | val id: Int,
5 | val title: String,
6 | val episodes: List
7 | ) {
8 | companion object {
9 | fun fromSection(section: dev.aaa1115910.biliapi.http.entity.video.UgcSeason.Section) =
10 | Section(
11 | id = section.id,
12 | title = section.title,
13 | episodes = section.episodes.map { Episode.fromEpisode(it) }
14 | )
15 |
16 | fun fromSection(section: bilibili.app.view.v1.Section) = Section(
17 | id = section.id.toInt(),
18 | title = section.title,
19 | episodes = section.episodesList.map { Episode.fromEpisode(it) }
20 | )
21 |
22 | fun fromModule(module: dev.aaa1115910.biliapi.http.entity.season.AppSeasonData.Module) =
23 | Section(
24 | id = module.id,
25 | title = module.title,
26 | episodes = module.data.episodes.map { Episode.fromEpisode(it) }
27 | )
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/danmaku/DanmakuResponse.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.danmaku
2 |
3 |
4 | data class DanmakuResponse(
5 | val chatserver: String,
6 | val chatId: Long,
7 | val maxLimit: Int,
8 | val state: Int,
9 | val realName: Int,
10 | val source: String,
11 | val data: List = emptyList()
12 | )
13 |
14 | data class DanmakuData(
15 | val time: Float,
16 | val type: Int,
17 | val size: Int,
18 | val color: Int,
19 | val timestamp: Int,
20 | val pool: Int,
21 | val midHash: String,
22 | val dmid: Long,
23 | val level: Int,
24 | val text: String
25 | ) {
26 | companion object {
27 | fun fromString(p: String, text: String): DanmakuData {
28 | val data = p.split(",")
29 | return DanmakuData(
30 | time = data[0].toFloat(),
31 | type = data[1].toInt(),
32 | size = data[2].toInt(),
33 | color = data[3].toInt(),
34 | timestamp = data[4].toInt(),
35 | pool = data[5].toInt(),
36 | midHash = data[6],
37 | dmid = data[7].toLong(),
38 | level = data[8].toInt(),
39 | text = text
40 | )
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/index/IndexFilterArea.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.index
2 |
3 | object IndexFilterArea {
4 | private val areaFilter = mapOf(
5 | -1 to "全部",
6 | 1 to "中国大陆",
7 | 2 to "日本",
8 | 3 to "美国",
9 | 4 to "英国",
10 | 5 to "其他",
11 | 6 to "中国港台",
12 | 8 to "韩国",
13 | 9 to "法国",
14 | 10 to "泰国",
15 | 13 to "西班牙",
16 | 15 to "德国",
17 | 35 to "意大利",
18 | )
19 |
20 | private val movieAreaIds = listOf(
21 | -1, 1, 6, 3, 28, 9, 4, 15, 10, 35, 13, 5
22 | )
23 | private val tvAreaIds = listOf(
24 | -1, 1, 2, 3, 4, 10, 5
25 | )
26 |
27 | val movieAreas by lazy { movieAreaIds.associateWith { areaFilter[it]!! } }
28 | val tvAreas by lazy { tvAreaIds.associateWith { areaFilter[it]!! } }
29 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/index/IndexFilterProducerId.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.index
2 |
3 | object IndexFilterProducerId {
4 | private val producerIdFilter = mapOf(
5 | -1 to "全部",
6 | 1 to "BBC",
7 | 2 to "NHK",
8 | 3 to "SKY",
9 | 4 to "央视",
10 | 5 to "ITV",
11 | 6 to "历史频道",
12 | 7 to "探索频道",
13 | 8 to "卫视",
14 | 9 to "自制",
15 | 10 to "ZDF",
16 | 11 to "合作机构",
17 | 12 to "国内其他",
18 | 13 to "国外其他",
19 | 14 to "国家地理",
20 | 15 to "索尼",
21 | 16 to "环球",
22 | 17 to "派拉蒙",
23 | 18 to "华纳",
24 | 19 to "迪士尼",
25 | 20 to "HBO",
26 |
27 | )
28 |
29 | private val producerIdIds = listOf(
30 | -1, 4, 1, 7, 14, 2, 6, 8, 9, 5, 3, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20
31 | )
32 |
33 | val producerIds by lazy { producerIdIds.associateWith { producerIdFilter[it]!! } }
34 | }
35 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/index/IndexOrder.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.index
2 |
3 | enum class IndexOrder(val id: Int) {
4 | UpdateTime(0), DanmakuCount(1), PlayCount(2), FollowCount(3),
5 | Score(4), StartTime(5), PublishTime(6)
6 | }
7 |
8 | private val animeIds = listOf(3, 0, 4, 2, 5)
9 | private val guochuangIds = listOf(3, 0, 4, 2, 5)
10 | private val varietyIds = listOf(2, 0, 6, 4, 1)
11 | private val tvIds = listOf(2, 0, 1, 3, 4)
12 | private val movieIds = listOf(2, 0, 6, 4)
13 | private val documentaryIds = listOf(2, 4, 0, 6, 1)
14 |
15 | val animeIndexOrders by lazy { animeIds.map { IndexOrder.entries[it] } }
16 | val guochuangIndexOrders by lazy { guochuangIds.map { IndexOrder.entries[it] } }
17 | val varietyIndexOrders by lazy { varietyIds.map { IndexOrder.entries[it] } }
18 | val tvIndexOrders by lazy { tvIds.map { IndexOrder.entries[it] } }
19 | val movieIndexOrders by lazy { movieIds.map { IndexOrder.entries[it] } }
20 | val documentaryIndexOrders by lazy { documentaryIds.map { IndexOrder.entries[it] } }
21 |
22 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/live/LiveDanmuInfoResponse.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.live
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class DanmuInfoData(
8 | val group: String,
9 | @SerialName("business_id")
10 | val businessId: Int,
11 | @SerialName("refresh_row_factor")
12 | val refreshRowFactor: Float,
13 | @SerialName("refresh_rate")
14 | val refreshRate: Int,
15 | @SerialName("max_delay")
16 | val maxDelay: Int,
17 | val token: String,
18 | @SerialName("host_list")
19 | val hostList: List = emptyList()
20 | )
21 |
22 | @Serializable
23 | data class HostListItem(
24 | val host: String,
25 | val port: Int,
26 | @SerialName("wss_port")
27 | val wssPort: Int,
28 | @SerialName("ws_port")
29 | val wsPort: Int
30 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/live/LiveEvent.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.live
2 |
3 | interface LiveEvent
4 |
5 | data class DanmakuEvent(
6 | val content: String,
7 | val mid: Long,
8 | val username: String,
9 | val medalName: String? = null,
10 | val medalLevel: Int? = null
11 | ) : LiveEvent
12 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/login/Captcha.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.login
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 申请 captcha 验证码结果
8 | *
9 | * @param type 验证方式 用于判断使用哪一种验证方式,目前所见只有极验 geetest:极验
10 | * @param token 登录 API token 与 captcha 无关,与登录接口有关
11 | * @param geetest 极验 captcha 数据
12 | * @param tencent 作用尚不明确
13 | */
14 | @Serializable
15 | data class CaptchaData(
16 | val type: String,
17 | val token: String,
18 | val geetest: Geetest,
19 | val tencent: Tencent
20 | ) {
21 | /**
22 | * 极验captcha数据
23 | *
24 | * @param gt 极验id 一般为固定值
25 | * @param challenge 极验KEY 由B站后端产生用于人机验证
26 | */
27 | @Serializable
28 | data class Geetest(
29 | val challenge: String,
30 | val gt: String
31 | )
32 |
33 | @Serializable
34 | data class Tencent(
35 | @SerialName("appid")
36 | val appId: String
37 | )
38 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/login/qr/WebQR.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.login.qr
2 |
3 | import io.ktor.http.Cookie
4 | import kotlinx.serialization.SerialName
5 | import kotlinx.serialization.Serializable
6 | import kotlinx.serialization.Transient
7 |
8 | @Serializable
9 | data class RequestWebQRData(
10 | val url: String,
11 | @SerialName("qrcode_key")
12 | val qrcodeKey: String
13 | )
14 |
15 |
16 | @Serializable
17 | data class QRLoginResponse(
18 | val code: Int,
19 | val message: String,
20 | val ttl: Int,
21 | val data: WebQRLoginData,
22 | @Transient
23 | var cookies: List = emptyList()
24 | )
25 |
26 | @Serializable
27 | data class WebQRLoginData(
28 | val url: String,
29 | @SerialName("refresh_token")
30 | val refreshToken: String,
31 | val timestamp: Long,
32 | val code: Int,
33 | val message: String
34 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/login/sms/SendSmsResponse.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.login.sms
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 发送验证码结果
8 | */
9 | @Serializable
10 | data class SendSmsResponse(
11 | @SerialName("captcha_key")
12 | val captchaKey: String,
13 | @SerialName("recaptcha_url")
14 | val recaptchaUrl: String
15 | )
16 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/region/RegionDynamicList.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.region
2 |
3 |
4 | import kotlinx.serialization.SerialName
5 | import kotlinx.serialization.Serializable
6 |
7 | @Serializable
8 | data class RegionDynamicList(
9 | @SerialName("cbottom")
10 | val cBottom: Long,
11 | @SerialName("ctop")
12 | val cTop: Long,
13 | val new: List-
14 | ) {
15 | @Serializable
16 | data class Item(
17 | val cover: String,
18 | @SerialName("cover_left_icon_1")
19 | val coverLeftIcon1: Int,
20 | @SerialName("cover_left_text_1")
21 | val coverLeftText1: String,
22 | val danmaku: Int? = null,
23 | val duration: Int,
24 | val face: String,
25 | val favourite: Int? = null,
26 | val goto: String,
27 | val like: Int? = null,
28 | val name: String,
29 | val param: String,
30 | val play: Int? = null,
31 | @SerialName("pubdate")
32 | val pubDate: Int,
33 | val reply: Int? = null,
34 | val rid: Int,
35 | @SerialName("rname")
36 | val rName: String,
37 | val title: String,
38 | val uri: String
39 | )
40 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/search/SearchCost.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.search
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class SearchCost(
8 | @SerialName("params_check")
9 | val paramsCheck: String,
10 | @SerialName("is_risk_query")
11 | val isRiskQuery: String? = null,
12 | @SerialName("illegal_handler")
13 | val illegalHandler: String? = null,
14 | @SerialName("as_response_format")
15 | val asResponseFormat: String? = null,
16 | @SerialName("mysql_request")
17 | val mysqlRequest: String? = null,
18 | @SerialName("as_request")
19 | val asRequest: String? = null,
20 | @SerialName("save_cache")
21 | val saveCache: String? = null,
22 | @SerialName("as_request_format")
23 | val asRequestFormat: String? = null,
24 | @SerialName("hotword_request")
25 | val hotwordRequest: String? = null,
26 | @SerialName("hotword_request_format")
27 | val hotwordRequestFormat: String? = null,
28 | @SerialName("hotword_response_format")
29 | val hotwordResponseFormat: String? = null,
30 | @SerialName("deserialize_response")
31 | val deserializeResponses: String? = null,
32 | val total: String,
33 | @SerialName("main_handler")
34 | val mainHandler: String? = null,
35 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/season/Follow.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.season
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class SeasonFollowData(
7 | val fmid: Int,
8 | val relation: Boolean,
9 | val status: Int,
10 | val toast: String
11 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/season/SeasonSection.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.season
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonArray
6 |
7 | /**
8 | * 板块 花絮、PV、番外等非正片内容
9 | *
10 | * @param attr
11 | * @param episodeId
12 | * @param episodeIds
13 | * @param episodes 板块内容
14 | * @param id 板块id
15 | * @param title 板块标题
16 | * @param type
17 | */
18 | @Serializable
19 | data class SeasonSection(
20 | val attr: Int,
21 | @SerialName("episode_id")
22 | val episodeId: Int,
23 | @SerialName("episode_ids")
24 | val episodeIds: JsonArray? = null,
25 | val episodes: List = emptyList(),
26 | val id: Int,
27 | val title: String,
28 | val type: Int
29 | )
30 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/LevelInfo.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 等级信息
8 | *
9 | * @param currentLevel 当前等级 0-6级
10 | * @param currentMin 当前等级经验最低值
11 | * @param currentExp 当前经验
12 | * @param nextExp 升级下一等级需达到的经验
13 | */
14 | @Serializable
15 | data class LevelInfo(
16 | @SerialName("current_level")
17 | val currentLevel: Int,
18 | @SerialName("current_min")
19 | val currentMin: Int,
20 | @SerialName("current_exp")
21 | val currentExp: Int,
22 | @SerialName("next_exp")
23 | val nextExp: Int
24 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/Nameplate.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 勋章
8 | *
9 | * @param nid 勋章id
10 | * @param name 勋章名称
11 | * @param image 勋章图标
12 | * @param imageSmall 勋章图标(小)
13 | * @param level 勋章等级
14 | * @param condition 获取条件
15 | */
16 | @Serializable
17 | data class Nameplate(
18 | val nid: Int,
19 | val name: String,
20 | val image: String,
21 | @SerialName("image_small")
22 | val imageSmall: String,
23 | val level: String,
24 | val condition: String
25 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/Official.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * 认证信息
7 | *
8 | * @param role 认证类型 0:无 1 2 7 9:个人认证 3 4 5 6:机构认证
9 | * @param title 认证信息 无为空
10 | * @param desc 认证备注 无为空
11 | * @param type 是否认证 -1:无 0:个人认证 1:机构认证
12 | */
13 | @Serializable
14 | data class Official(
15 | val role: Int,
16 | val title: String,
17 | val desc: String,
18 | val type: Int
19 | )
20 |
21 | /**
22 | * 认证信息
23 | *
24 | * @param type 是否认证 -1:无 0:认证
25 | * @param desc 认证信息 无为空
26 | */
27 | @Serializable
28 | data class OfficialVerify(
29 | val type: Int,
30 | val desc: String
31 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/Pendant.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 头像框
8 | *
9 | * @param pid 头像框id
10 | * @param name 头像框名称
11 | * @param image 头像框图片url
12 | * @param expire 过期时间 此接口返回恒为0
13 | * @param imageEnhance 头像框图片url
14 | * @param imageEnhanceFrame 头像框图片逐帧序列url
15 | */
16 | @Serializable
17 | data class Pendant(
18 | val pid: Int,
19 | val name: String,
20 | val image: String,
21 | val expire: Int = 0,
22 | @SerialName("image_enhance")
23 | val imageEnhance: String? = null,
24 | @SerialName("image_enhance_frame")
25 | val imageEnhanceFrame: String? = null
26 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/Profession.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 专业资质信息
8 | *
9 | * @param name 资质名称
10 | * @param department 职位
11 | * @param title 所属机构
12 | * @param isShow 是否显示 0:不显示 1:显示
13 | */
14 | @Serializable
15 | data class Profession(
16 | val name: String,
17 | val department: String,
18 | val title: String,
19 | @SerialName("is_show")
20 | val isShow: Int
21 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/Staff.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * 创作者个人信息
7 | *
8 | * @param mid 成员mid
9 | * @param title 成员名称
10 | * @param name 成员昵称
11 | * @param face 成员头像url
12 | * @param vip 成员大会员状态
13 | * @param official 成员认证信息
14 | * @param follower 成员粉丝数
15 | */
16 | @Serializable
17 | data class Staff(
18 | val mid: Long,
19 | val title: String,
20 | val name: String,
21 | val face: String,
22 | val vip: Vip,
23 | val official: Official,
24 | val follower: Int
25 | )
26 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/UserGarb.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 用户头像挂件
8 | *
9 | * @param urlImageAniCut
10 | */
11 | @Serializable
12 | data class UserGarb(
13 | @SerialName("url_image_ani_cut")
14 | val urlImageAniCut: String
15 | )
16 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/UserHonours.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class UserHonours(
7 | val mid: Long,
8 | val colour: Colour? = null,
9 | val tags: List = emptyList()
10 | ) {
11 | @Serializable
12 | data class Colour(
13 | val dark: String,
14 | val normal: String
15 | )
16 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/favorite/CntInfo.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user.favorite
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * @param collect 收藏数
8 | * @param play 播放数
9 | * @param thumbUp 点赞数
10 | * @param share 分享数
11 | */
12 | @Serializable
13 | data class CntInfo(
14 | val collect: Int,
15 | val play: Int,
16 | val danmaku: Int = 0,
17 | @SerialName("thumb_up")
18 | val thumbUp: Int = 0,
19 | val share: Int = 0
20 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/favorite/FavoriteFolderInfoListData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user.favorite
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 收藏夹信息及内容
8 | *
9 | * @param info 收藏夹元数据
10 | * @param medias 收藏夹内容
11 | * @param hasMore 还有更多数据
12 | */
13 | @Serializable
14 | data class FavoriteFolderInfoListData(
15 | val info: FavoriteFolderInfo,
16 | val medias: List = emptyList(),
17 | @SerialName("has_more")
18 | val hasMore: Boolean
19 | )
20 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/favorite/Upper.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user.favorite
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 收藏夹上传者
8 | *
9 | * @param mid 创建者mid
10 | * @param name 创建者昵称
11 | * @param face 创建者头像url
12 | * @param followed 是否已关注创建者
13 | * @param vipType 会员类别 0:无 1:月大会员 2:年度及以上大会员
14 | * @param vipStatue 会员开通状态 0:无 1:有
15 | */
16 | @Serializable
17 | data class Upper(
18 | val mid: Long,
19 | val name: String,
20 | val face: String,
21 | val followed: Boolean = false,
22 | @SerialName("vip_type")
23 | val vipType: Int = 0,
24 | @SerialName("vip_statue")
25 | val vipStatue: Int = 0
26 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/favorite/UserFavoriteFoldersData.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user.favorite
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | /**
7 | * 指定用户创建的所有收藏夹信息
8 | *
9 | * @param count 创建的收藏夹总数
10 | * @param list 创建的收藏夹列表
11 | */
12 | @Serializable
13 | data class UserFavoriteFoldersData(
14 | val count: Int,
15 | val list: List = emptyList()
16 | ) {
17 | /**
18 | * 用户收藏夹信息
19 | *
20 | * @param id 收藏夹mlid(完整id) 收藏夹原始id+创建者mid尾号2位
21 | * @param fid 收藏夹原始id
22 | * @param mid 创建者mid
23 | * @param attr 属性位(?)
24 | * @param title 收藏夹标题
25 | * @param favState 目标id是否存在于该收藏夹 存在于该收藏夹:1 不存在于该收藏夹:0
26 | * @param mediaCount 收藏夹内容数量
27 | */
28 | @Serializable
29 | data class UserFavoriteFolder(
30 | val id: Long,
31 | val fid: Long,
32 | val mid: Long,
33 | val attr: Int,
34 | val title: String,
35 | @SerialName("fav_state")
36 | val favState: Int,
37 | @SerialName("media_count")
38 | val mediaCount: Int
39 | )
40 | }
41 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/garb/CardBg.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user.garb
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonObject
6 |
7 | @Serializable
8 | data class CardBg(
9 | @SerialName("act_id")
10 | val actId: Int,
11 | val level: Int,
12 | @SerialName("bg_no")
13 | val bgNo: Int,
14 | val color: String,
15 | @SerialName("no_prefix")
16 | val noPrefix: String,
17 | @SerialName("no_color_format")
18 | val noColorFormat: JsonObject? = null
19 | )
20 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/user/garb/Equip.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.user.garb
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonObject
6 |
7 | @Serializable
8 | data class Equip(
9 | val item: Item? = null,
10 | val index: Int,
11 | val fan: JsonObject? = null,
12 | @SerialName("is_diy")
13 | val isDiy: Int,
14 | @SerialName("card_bg")
15 | val cardBg: CardBg? = null,
16 | @SerialName("previous_item")
17 | val previousItem: Item? = null,
18 | @SerialName("previous_index")
19 | val previousIndex: Int,
20 | @SerialName("previous_fan")
21 | val previousFan: JsonObject? = null,
22 | @SerialName("previous_is_diy")
23 | val previousIsDiy: Int,
24 | @SerialName("previous_card_bg")
25 | val previousCardBg: CardBg? = null,
26 | )
27 |
28 | enum class EquipPart(val value: String) {
29 | Card("card"),
30 | CardBg("card_bg"),
31 | Loading("loading"),
32 | PlayerIcon("play_icon"),
33 | Pendant("pendant"),
34 | Thumbup("thumbup"),
35 | }
36 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/video/AddCoin.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.video
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * 投币时顺便点赞的结果
7 | *
8 | * @param like 是否点赞成功 true:成功 false:失败 已赞过则附加点赞失败
9 | */
10 | @Serializable
11 | data class AddCoin(
12 | val like: Boolean
13 | )
14 |
15 | /**
16 | * 检查是否投币
17 | *
18 | * @param multiply 投币枚数 未投币为0
19 | */
20 | @Serializable
21 | data class CheckSentCoin(
22 | val multiply:Int
23 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/video/PopularVideosResponse.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.video
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class PopularVideoData(
8 | val list: List,
9 | @SerialName("no_more")
10 | val noMore: Boolean
11 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/video/SetVideoFavorite.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.video
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | /**
6 | * 添加/移除收藏
7 | *
8 | * @param prompt 是否为未关注用户收藏 false:否 true:是
9 | */
10 | @Serializable
11 | data class SetVideoFavorite(
12 | val prompt:Boolean
13 | )
14 |
15 | /**
16 | * 检查是否被收藏
17 | *
18 | * @param count 1
19 | * @param favoured 是否收藏 true:已收藏 false:未收藏
20 | */
21 | @Serializable
22 | data class CheckVideoFavoured(
23 | val count:Int,
24 | val favoured:Boolean
25 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/video/VideoShot.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.video
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 | import kotlinx.serialization.json.JsonElement
6 |
7 | @Serializable
8 | data class VideoShot(
9 | @SerialName("pvdata")
10 | val pvData: String? = null,
11 | @SerialName("img_x_len")
12 | val imgXLen: Int = 10,
13 | @SerialName("img_y_len")
14 | val imgYLen: Int = 10,
15 | @SerialName("img_x_size")
16 | val imgXSize: Int = 0,
17 | @SerialName("img_y_size")
18 | val imgYSize: Int = 0,
19 | val image: List = emptyList(),
20 | val index: List? = null,
21 | @SerialName("video_shots")
22 | var videoShots: JsonElement? = null,
23 | var indexs: JsonElement? = null
24 | )
25 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/web/Hover.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.web
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class Hover(
7 | val text: List,
8 | val img: String
9 | )
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/entity/web/Nav.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.entity.web
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class NavResponseData(
8 | val isLogin: Boolean,
9 | @SerialName("wbi_img")
10 | val wbiImg: WbiImg
11 | ) {
12 | @Serializable
13 | data class WbiImg(
14 | @SerialName("img_url")
15 | val imgUrl: String,
16 | @SerialName("sub_url")
17 | val subUrl: String
18 | ) {
19 | fun getImgKey(): String = imgUrl.split("/").last().split(".").first()
20 | fun getSubKey(): String = subUrl.split("/").last().split(".").first()
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/util/BiliAppConf.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.util
2 |
3 | object BiliAppConf {
4 | const val GRPC_HOST = "grpc.biliapi.net"
5 | const val GRPC_PORT = 443
6 | const val APP_ID = 5
7 | const val APP_BUILD_CODE = 6830300
8 | const val CHANNEL = "bili"
9 | const val MOBI_APP = "android_hd"
10 | const val DEVICE = ""
11 | const val PLATFORM = "android"
12 | const val TIMEZONE = "Asia/Shanghai"
13 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/util/Buvid.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.util
2 |
3 | import java.math.BigInteger
4 | import java.security.MessageDigest
5 |
6 | fun generateBuvid(): String {
7 | val mac = mutableListOf()
8 | for (i in 0 until 6) {
9 | val min = 0
10 | val max = 0xff
11 | val num = (Math.random() * (max - min + 1) + min).toInt().toString(16)
12 | mac.add(num)
13 | }
14 | val md5 = md5(mac.joinToString(":"))
15 | val md5Arr = md5.split("").toTypedArray()
16 | return "XY${md5Arr[2]}${md5Arr[12]}${md5Arr[22]}$md5"
17 | }
18 |
19 | fun md5(input: String): String {
20 | val md = MessageDigest.getInstance("MD5")
21 | val messageDigest = md.digest(input.toByteArray())
22 | val no = BigInteger(1, messageDigest)
23 | var hashText = no.toString(16)
24 | while (hashText.length < 32) {
25 | hashText = "0$hashText"
26 | }
27 | return hashText
28 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/http/util/Zlib.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http.util
2 |
3 | import io.ktor.utils.io.core.use
4 | import java.io.ByteArrayOutputStream
5 | import java.util.zip.Deflater
6 | import java.util.zip.Inflater
7 |
8 | fun ByteArray.zlibCompress(): ByteArray {
9 | val output = ByteArray(this.size * 4)
10 | val compressor = Deflater().apply {
11 | setInput(this@zlibCompress)
12 | finish()
13 | }
14 | val compressedDataLength: Int = compressor.deflate(output)
15 | return output.copyOfRange(0, compressedDataLength)
16 | }
17 |
18 | fun ByteArray.zlibDecompress(): ByteArray {
19 | val inflater = Inflater()
20 | val outputStream = ByteArrayOutputStream()
21 | return outputStream.use {
22 | val buffer = ByteArray(1024)
23 | inflater.setInput(this)
24 | var count = -1
25 | while (count != 0) {
26 | count = inflater.inflate(buffer)
27 | outputStream.write(buffer, 0, count)
28 | }
29 | inflater.end()
30 | outputStream.toByteArray()
31 | }
32 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/repositories/AuthRepository.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.repositories
2 |
3 | class AuthRepository {
4 | var sessionData: String? = null
5 | var biliJct: String? = null
6 | var accessToken: String? = null
7 | var mid: Long? = null
8 | var buvid3: String? = null
9 | var buvid: String? = null
10 | }
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/repositories/ChannelRepository.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.repositories
2 |
3 | import dev.aaa1115910.biliapi.grpc.utils.generateChannel
4 | import io.grpc.ManagedChannel
5 |
6 | class ChannelRepository {
7 | // grpc.biliapi.net
8 | var defaultChannel: ManagedChannel? = null
9 |
10 | // custom proxy server
11 | var proxyChannel: ManagedChannel? = null
12 |
13 | fun initDefaultChannel(accessKey: String, buvid: String) {
14 | defaultChannel?.shutdownNow()
15 | defaultChannel = generateChannel(accessKey, buvid)
16 | }
17 |
18 | fun initProxyChannel(accessKey: String, buvid: String, proxyServer: String) {
19 | proxyChannel?.shutdownNow()
20 | val proxyServerSpilt = proxyServer.split(":")
21 | val endPoint = proxyServerSpilt.first()
22 | val port = proxyServerSpilt.getOrNull(1)?.toInt()
23 | proxyChannel = if (port != null) {
24 | generateChannel(accessKey, buvid, endPoint, port, port == 443)
25 | } else {
26 | generateChannel(accessKey, buvid, endPoint)
27 | }
28 | //proxyChannel = generateChannel(accessKey, buvid, "192.168.2.125", 8080, false)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/repositories/UgcRepository.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.repositories
2 |
3 | import dev.aaa1115910.biliapi.entity.ugc.UgcType
4 | import dev.aaa1115910.biliapi.entity.ugc.region.UgcRegionData
5 | import dev.aaa1115910.biliapi.entity.ugc.region.UgcRegionListData
6 | import dev.aaa1115910.biliapi.http.BiliHttpApi
7 |
8 | class UgcRepository(
9 | private val authRepository: AuthRepository
10 | ) {
11 | suspend fun getRegionData(ugcType: UgcType): UgcRegionData {
12 | val responseData = BiliHttpApi.getRegionDynamic(
13 | rid = ugcType.rid,
14 | accessKey = authRepository.accessToken ?: "",
15 | ).getResponseData()
16 | val data = UgcRegionData.fromRegionDynamic(responseData)
17 | return data
18 | }
19 |
20 | suspend fun getRegionMoreData(ugcType: UgcType): UgcRegionListData {
21 | val responseData = BiliHttpApi.getRegionDynamicList(
22 | rid = ugcType.rid,
23 | accessKey = authRepository.accessToken ?: "",
24 | ).getResponseData()
25 | val data = UgcRegionListData.fromRegionDynamicList(responseData)
26 | return data
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/util/Extends.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.util
2 |
3 | fun String.convertStringTimeToSeconds(): Int {
4 | val parts = this.split(":")
5 | val hours = if (parts.size == 3) parts[0].toInt() else 0
6 | val minutes = parts[parts.size - 2].toInt()
7 | val seconds = parts[parts.size - 1].toInt()
8 | return (hours * 3600) + (minutes * 60) + seconds
9 | }
10 |
11 | fun Long.toBv(): String = AvBvConverter.av2bv(this)
12 | fun String.toAv(): Long = AvBvConverter.bv2av(this)
--------------------------------------------------------------------------------
/bili-api/src/main/kotlin/dev/aaa1115910/biliapi/util/UrlUtil.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.util
2 |
3 | import io.ktor.http.Url
4 |
5 | object UrlUtil {
6 | fun isVideoUrl(url: String): Boolean {
7 | return url.startsWith("bilibili://video/")
8 | || url.startsWith("https://www.bilibili.com/video/")
9 | }
10 |
11 | fun parseAidFromUrl(url: String): Long {
12 | if (url.startsWith("bilibili://video/")) {
13 | return url.split("/").last().toLong()
14 | } else {
15 | val pathSegments = Url(url).rawSegments
16 | val videoSegmentIndex = pathSegments.indexOf("video")
17 | val videoId = pathSegments[videoSegmentIndex + 1]
18 | return if (videoId.startsWith("BV")) {
19 | AvBvConverter.bv2av(videoId)
20 | } else {
21 | videoId.drop(2).toLong()
22 | }
23 | }
24 | }
25 |
26 | fun parseBvidFromUrl(url: String) = parseAidFromUrl(url).toBv()
27 | }
28 |
--------------------------------------------------------------------------------
/bili-api/src/test/kotlin/dev/aaa1115910/biliapi/http/BiliLiveHttpApiTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import org.junit.jupiter.api.Assertions
5 | import org.junit.jupiter.api.Test
6 |
7 | class BiliLiveHttpApiTest {
8 | @Test
9 | fun `get history live room danmaku`() {
10 | Assertions.assertDoesNotThrow {
11 | runBlocking {
12 | val response = BiliLiveHttpApi.getLiveDanmuHistory(roomId = 22739471)
13 | println(response)
14 | }
15 | }
16 | }
17 |
18 | @Test
19 | fun `get live event websocket connect url and token`() {
20 | Assertions.assertDoesNotThrow {
21 | runBlocking {
22 | val response = BiliLiveHttpApi.getLiveDanmuInfo(roomId = 22739471)
23 | println(response)
24 | }
25 | }
26 | }
27 |
28 | @Test
29 | fun `get live room info`() {
30 | Assertions.assertDoesNotThrow {
31 | runBlocking {
32 | val response = BiliLiveHttpApi.getLiveRoomPlayInfo(roomId = 22739471)
33 | println(response)
34 | }
35 | }
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/bili-api/src/test/kotlin/dev/aaa1115910/biliapi/http/BiliPlusHttpApiTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.http
2 |
3 | import kotlinx.coroutines.runBlocking
4 | import org.junit.jupiter.api.Test
5 |
6 | class BiliPlusHttpApiTest {
7 |
8 | @Test
9 | fun `get season video view`() = runBlocking {
10 | val result = BiliPlusHttpApi.view(955635143)
11 | println(result)
12 | }
13 |
14 | @Test
15 | fun `get normal video view`() = runBlocking {
16 | val result = BiliPlusHttpApi.view(955635143)
17 | println(result)
18 | }
19 |
20 | @Test
21 | fun `get not found video view`() = runBlocking {
22 | val result = BiliPlusHttpApi.view(1)
23 | println(result)
24 | }
25 |
26 | @Test
27 | fun `get season id by avid`() = runBlocking {
28 | val seasonId = BiliPlusHttpApi.getSeasonIdByAvid(314583081)
29 | println(seasonId)
30 | }
31 | }
--------------------------------------------------------------------------------
/bili-api/src/test/kotlin/dev/aaa1115910/biliapi/websocket/LiveDataWebSocketTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.biliapi.websocket
2 |
3 | import kotlinx.coroutines.delay
4 | import kotlinx.coroutines.runBlocking
5 | import org.junit.jupiter.api.Test
6 |
7 | internal class LiveDataWebSocketTest {
8 |
9 | @Test
10 | fun connectLiveEvent() {
11 | runBlocking {
12 | LiveDataWebSocket.connectLiveEvent(5555) {
13 | println(it)
14 | }
15 | for (i in 1..10) {
16 | delay(1_000)
17 | }
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/bili-api/src/test/resources/3540266_25_2.exp.mobmask:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/bili-api/src/test/resources/3540266_25_2.exp.mobmask
--------------------------------------------------------------------------------
/bili-api/src/test/resources/3540266_25_2.exp.webmask:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/bili-api/src/test/resources/3540266_25_2.exp.webmask
--------------------------------------------------------------------------------
/bili-subtitle/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/bili-subtitle/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(gradleLibs.plugins.kotlin.jvm)
3 | alias(gradleLibs.plugins.kotlin.serialization)
4 | }
5 |
6 | dependencies {
7 | implementation(libs.kotlinx.serialization)
8 | testImplementation(libs.kotlin.test)
9 | }
10 |
11 | tasks.test {
12 | useJUnitPlatform()
13 | }
14 |
--------------------------------------------------------------------------------
/bili-subtitle/src/main/kotlin/dev/aaa1115910/bilisubtitle/entity/BiliSubtitle.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bilisubtitle.entity
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class BiliSubtitle(
8 | @SerialName("font_size")
9 | val fontSize: Float? = null,
10 | @SerialName("font_color")
11 | val fontColor: String? = null,
12 | @SerialName("background_alpha")
13 | val backgroundAlpha: Float? = null,
14 | @SerialName("background_color")
15 | val backgroundColor: String? = null,
16 | @SerialName("Stroke")
17 | val stroke: String? = null,
18 | val type: String? = null,
19 | val lang: String? = null,
20 | val version: String? = null,
21 | val body: List = emptyList()
22 | )
23 |
24 | @Serializable
25 | data class BiliSubtitleItem(
26 | val from: Float,
27 | val to: Float,
28 | val sid: Int? = null,
29 | val location: Int,
30 | val content: String,
31 | val music: Float? = null
32 | )
--------------------------------------------------------------------------------
/bili-subtitle/src/main/kotlin/dev/aaa1115910/bilisubtitle/entity/SrtSubtitle.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bilisubtitle.entity
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class SrtSubtitle(
7 | val content: List = emptyList()
8 | )
9 |
10 | @Serializable
11 | data class SrtSubtitleItem(
12 | val index: Int,
13 | val from: String,
14 | val to: String,
15 | val content: String
16 | ) {
17 | fun toRaw() = """
18 | $index
19 | $from --> $to
20 | $content
21 |
22 | """.trimIndent()
23 | }
24 |
--------------------------------------------------------------------------------
/bili-subtitle/src/main/kotlin/dev/aaa1115910/bilisubtitle/entity/SubtitleItem.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bilisubtitle.entity
2 |
3 | data class SubtitleItem(
4 | val from: Timestamp,
5 | val to: Timestamp,
6 | val content: String
7 | ) {
8 | fun isShowing(time: Long) = from.totalMills <= time && to.totalMills >= time
9 | }
10 |
--------------------------------------------------------------------------------
/bili-subtitle/src/test/kotlin/dev/aaa1115910/bilisubtitle/SubtitleEncoderTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bilisubtitle
2 |
3 | import java.io.File
4 | import kotlin.test.Test
5 |
6 | class SubtitleEncoderTest {
7 |
8 | @Test
9 | fun `encode to bcc`() {
10 | val fileContent = this::class.java.getResource("/example.srt")?.readText()!!
11 | val data = SubtitleParser.fromSrtString(fileContent)
12 | val result = SubtitleEncoder.encodeToBcc(data)
13 | val outputFile = File("build/output.bcc")
14 | outputFile.createNewFile()
15 | outputFile.writeText(result)
16 | }
17 |
18 | @Test
19 | fun `encode to srt`() {
20 | val fileContent = this::class.java.getResource("/example.bcc")?.readText()!!
21 | val data = SubtitleParser.fromBccString(fileContent)
22 | val result = SubtitleEncoder.encodeToSrt(data)
23 | val outputFile = File("build/output.srt")
24 | outputFile.createNewFile()
25 | outputFile.writeText(result)
26 | }
27 | }
--------------------------------------------------------------------------------
/bili-subtitle/src/test/kotlin/dev/aaa1115910/bilisubtitle/SubtitleParserTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bilisubtitle
2 |
3 | import kotlin.test.Test
4 |
5 | class SubtitleParserTest {
6 | @Test
7 | fun `read bcc subtitle`() {
8 | val fileContent = this::class.java.getResource("/example.bcc")?.readText()!!
9 | val result = SubtitleParser.fromBccString(fileContent)
10 | println(result)
11 | }
12 |
13 | @Test
14 | fun `read srt subtitle`() {
15 | val fileContent = this::class.java.getResource("/example.srt")?.readText()!!
16 | val result = SubtitleParser.fromSrtString(fileContent)
17 | println(result)
18 | }
19 | }
--------------------------------------------------------------------------------
/bili-subtitle/src/test/kotlin/dev/aaa1115910/bilisubtitle/entity/TimestampTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bilisubtitle.entity
2 |
3 | import kotlin.test.Test
4 |
5 | class TimestampTest {
6 | @Test
7 | fun `parse bcc time`() {
8 | val time = 7530.2f
9 | println(Timestamp.fromBccString(time))
10 | }
11 |
12 | @Test
13 | fun `parse srt time`() {
14 | val time = "01:03:17,775"
15 | println(Timestamp.fromSrtString(time))
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(gradleLibs.plugins.android.application) apply false
3 | alias(gradleLibs.plugins.android.library) apply false
4 | alias(gradleLibs.plugins.compose.compiler) apply false
5 | alias(gradleLibs.plugins.google.ksp) apply false
6 | alias(gradleLibs.plugins.kotlin.android) apply false
7 | alias(gradleLibs.plugins.kotlin.jvm) apply false
8 | alias(gradleLibs.plugins.kotlin.serialization) apply false
9 | alias(gradleLibs.plugins.versions)
10 | }
--------------------------------------------------------------------------------
/buildSrc/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/buildSrc/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-dsl`
3 | }
4 |
5 | repositories {
6 | mavenCentral()
7 | }
--------------------------------------------------------------------------------
/bv-player/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/bv-player/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/bv-player/consumer-rules.pro
--------------------------------------------------------------------------------
/bv-player/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/bv-player/src/androidTest/java/dev/aaa1115910/bv/player/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("dev.aaa1115910.bv.player.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/bv-player/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/bv-player/src/main/assets/GlobalSign ECC Root CA R5.crt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/bv-player/src/main/assets/GlobalSign ECC Root CA R5.crt
--------------------------------------------------------------------------------
/bv-player/src/main/kotlin/dev/aaa1115910/bv/player/Extends.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player
2 |
3 | import java.util.concurrent.TimeUnit
4 |
5 | fun Long.formatMinSec(): String {
6 | return if (this < 0L) {
7 | "..."
8 | } else {
9 | String.format(
10 | "%02d:%02d",
11 | TimeUnit.MILLISECONDS.toMinutes(this),
12 | TimeUnit.MILLISECONDS.toSeconds(this) -
13 | TimeUnit.MINUTES.toSeconds(
14 | TimeUnit.MILLISECONDS.toMinutes(this)
15 | )
16 | )
17 | }
18 | }
--------------------------------------------------------------------------------
/bv-player/src/main/kotlin/dev/aaa1115910/bv/player/VideoPlayerListener.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player
2 |
3 | interface VideoPlayerListener {
4 | /** 异常 */
5 | fun onError(error: Exception)
6 |
7 | /**
8 | * 准备
9 | */
10 | fun onReady()
11 |
12 | /** 播放 */
13 | fun onPlay()
14 |
15 | /** 暂停 */
16 | fun onPause()
17 |
18 | /** 缓冲中 */
19 | fun onBuffering()
20 |
21 | /** 播放结束 */
22 | fun onEnd()
23 |
24 | /** 后退 */
25 | fun onSeekBack(seekBackIncrementMs: Long)
26 |
27 | /** 前进 */
28 | fun onSeekForward(seekForwardIncrementMs: Long)
29 |
30 | }
--------------------------------------------------------------------------------
/bv-player/src/main/kotlin/dev/aaa1115910/bv/player/VideoPlayerOptions.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player
2 |
3 | data class VideoPlayerOptions(
4 | val userAgent: String? = null,
5 | val referer: String? = null,
6 | val enableFfmpegAudioRenderer: Boolean = false
7 | )
--------------------------------------------------------------------------------
/bv-player/src/main/kotlin/dev/aaa1115910/bv/player/factory/PlayerFactory.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player.factory
2 |
3 | import android.content.Context
4 | import dev.aaa1115910.bv.player.AbstractVideoPlayer
5 | import dev.aaa1115910.bv.player.VideoPlayerOptions
6 |
7 | abstract class PlayerFactory {
8 | abstract fun create(context: Context,options: VideoPlayerOptions): T
9 | }
--------------------------------------------------------------------------------
/bv-player/src/main/kotlin/dev/aaa1115910/bv/player/impl/exo/ExoPlayerFactory.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player.impl.exo
2 |
3 | import android.content.Context
4 | import dev.aaa1115910.bv.player.VideoPlayerOptions
5 | import dev.aaa1115910.bv.player.factory.PlayerFactory
6 |
7 | class ExoPlayerFactory : PlayerFactory() {
8 | override fun create(context: Context, options: VideoPlayerOptions): ExoMediaPlayer {
9 | return ExoMediaPlayer(context, options)
10 | }
11 | }
--------------------------------------------------------------------------------
/bv-player/src/test/java/dev/aaa1115910/bv/player/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package dev.aaa1115910.bv.player
2 |
3 |
4 | import kotlin.test.Test
5 | import kotlin.test.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/QcxFlora/BVG/bdf704e416e48023bf200261f328bc796abcbca7/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Nov 20 12:22:18 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | gradlePluginPortal()
6 | }
7 | resolutionStrategy {
8 | eachPlugin {
9 | when (requested.id.name) {
10 | "crashlytics" -> useModule("com.google.firebase:firebase-crashlytics-gradle:2.9.9")
11 | }
12 | }
13 | }
14 | }
15 | dependencyResolutionManagement {
16 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
17 | repositories {
18 | google()
19 | mavenCentral()
20 | maven("https://repo1.maven.org/maven2/")
21 | maven("https://androidx.dev/storage/compose-compiler/repository/")
22 | //maven("https://artifact.bytedance.com/repository/releases/")
23 | }
24 | versionCatalogs {
25 | create("androidx") { from(files("gradle/androidx.versions.toml")) }
26 | create("gradleLibs") { from(files("gradle/gradle.versions.toml")) }
27 | }
28 | }
29 | rootProject.name = "BV"
30 | include(":app")
31 | include(":bili-api")
32 | include(":bili-subtitle")
33 | include(":bv-player")
34 | include(":libs:av1Decoder")
35 | include(":libs:ffmpegDecoder")
36 | include(":libs:libVLC")
37 | include(":bili-api-grpc")
38 |
--------------------------------------------------------------------------------