Repository: xiaoyaocz/dart_simple_live Branch: master Commit: ba828e6783b1 Files: 436 Total size: 2.6 MB Directory structure: gitextract_y43zef6r/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug.yml │ │ ├── config.yml │ │ └── feature.yml │ └── workflows/ │ ├── publish_app_dev.yaml │ ├── publish_app_release.yml │ ├── publish_tv_app_dev.yaml │ └── publish_tv_app_release.yaml ├── .gitignore ├── .vscode/ │ └── settings.json ├── LICENSE ├── README.md ├── assets/ │ ├── app_version.json │ ├── play_config.json │ └── tv_app_version.json ├── simple_live_app/ │ ├── .fvmrc │ ├── .gitignore │ ├── .metadata │ ├── README.md │ ├── analysis_options.yaml │ ├── android/ │ │ ├── .gitignore │ │ ├── app/ │ │ │ ├── build.gradle.kts │ │ │ ├── proguard-rules.pro │ │ │ └── src/ │ │ │ ├── debug/ │ │ │ │ └── AndroidManifest.xml │ │ │ ├── main/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin/ │ │ │ │ │ └── com/ │ │ │ │ │ └── xycz/ │ │ │ │ │ └── simple_live/ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable-v21/ │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-anydpi-v26/ │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ └── ic_launcher_round.xml │ │ │ │ ├── values/ │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── values-night/ │ │ │ │ │ └── styles.xml │ │ │ │ └── xml/ │ │ │ │ └── network_security_config.xml │ │ │ └── profile/ │ │ │ └── AndroidManifest.xml │ │ ├── build/ │ │ │ └── reports/ │ │ │ └── problems/ │ │ │ └── problems-report.html │ │ ├── build.gradle.kts │ │ ├── gradle/ │ │ │ └── wrapper/ │ │ │ └── gradle-wrapper.properties │ │ ├── gradle.properties │ │ └── settings.gradle.kts │ ├── assets/ │ │ ├── lotties/ │ │ │ ├── empty.json │ │ │ ├── error.json │ │ │ └── loadding.json │ │ └── statement.txt │ ├── distribute_options.yaml │ ├── ios/ │ │ ├── .gitignore │ │ ├── Flutter/ │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Podfile │ │ ├── Runner/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── LaunchImage.imageset/ │ │ │ │ ├── Contents.json │ │ │ │ └── README.md │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ └── Runner-Bridging-Header.h │ │ ├── Runner.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata/ │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ └── Runner.xcscheme │ │ └── Runner.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ ├── lib/ │ │ ├── app/ │ │ │ ├── app_style.dart │ │ │ ├── constant.dart │ │ │ ├── controller/ │ │ │ │ ├── app_settings_controller.dart │ │ │ │ └── base_controller.dart │ │ │ ├── custom_throttle.dart │ │ │ ├── event_bus.dart │ │ │ ├── log.dart │ │ │ ├── sites.dart │ │ │ ├── utils/ │ │ │ │ ├── archive.dart │ │ │ │ ├── document.dart │ │ │ │ └── listen_fourth_button.dart │ │ │ └── utils.dart │ │ ├── main.dart │ │ ├── models/ │ │ │ ├── account/ │ │ │ │ └── bilibili_user_info_page.dart │ │ │ ├── db/ │ │ │ │ ├── follow_user.dart │ │ │ │ ├── follow_user.g.dart │ │ │ │ ├── follow_user_tag.dart │ │ │ │ ├── follow_user_tag.g.dart │ │ │ │ ├── history.dart │ │ │ │ └── history.g.dart │ │ │ ├── follow_user_item.dart │ │ │ ├── sync_client_info_model.dart │ │ │ └── version_model.dart │ │ ├── modules/ │ │ │ ├── category/ │ │ │ │ ├── category_controller.dart │ │ │ │ ├── category_list_controller.dart │ │ │ │ ├── category_list_view.dart │ │ │ │ ├── category_page.dart │ │ │ │ └── detail/ │ │ │ │ ├── category_detail_controller.dart │ │ │ │ └── category_detail_page.dart │ │ │ ├── follow_user/ │ │ │ │ ├── follow_user_controller.dart │ │ │ │ └── follow_user_page.dart │ │ │ ├── home/ │ │ │ │ ├── home_controller.dart │ │ │ │ ├── home_list_controller.dart │ │ │ │ ├── home_list_view.dart │ │ │ │ └── home_page.dart │ │ │ ├── indexed/ │ │ │ │ ├── indexed_controller.dart │ │ │ │ └── indexed_page.dart │ │ │ ├── live_room/ │ │ │ │ ├── live_room_controller.dart │ │ │ │ ├── live_room_page.dart │ │ │ │ └── player/ │ │ │ │ ├── player_controller.dart │ │ │ │ └── player_controls.dart │ │ │ ├── mine/ │ │ │ │ ├── account/ │ │ │ │ │ ├── account_controller.dart │ │ │ │ │ ├── account_page.dart │ │ │ │ │ └── bilibili/ │ │ │ │ │ ├── qr_login_controller.dart │ │ │ │ │ ├── qr_login_page.dart │ │ │ │ │ ├── web_login_controller.dart │ │ │ │ │ └── web_login_page.dart │ │ │ │ ├── history/ │ │ │ │ │ ├── history_controller.dart │ │ │ │ │ └── history_page.dart │ │ │ │ ├── mine_page.dart │ │ │ │ └── parse/ │ │ │ │ ├── parse_controller.dart │ │ │ │ └── parse_page.dart │ │ │ ├── other/ │ │ │ │ └── debug_log_page.dart │ │ │ ├── search/ │ │ │ │ ├── douyin/ │ │ │ │ │ ├── douyin_search_controller.dart │ │ │ │ │ └── douyin_search_view.dart │ │ │ │ ├── search_controller.dart │ │ │ │ ├── search_list_controller.dart │ │ │ │ ├── search_list_view.dart │ │ │ │ └── search_page.dart │ │ │ ├── settings/ │ │ │ │ ├── appstyle_setting_page.dart │ │ │ │ ├── auto_exit_settings_page.dart │ │ │ │ ├── danmu_settings_page.dart │ │ │ │ ├── danmu_shield/ │ │ │ │ │ ├── danmu_shield_controller.dart │ │ │ │ │ └── danmu_shield_page.dart │ │ │ │ ├── follow_settings_page.dart │ │ │ │ ├── indexed_settings/ │ │ │ │ │ ├── indexed_settings_controller.dart │ │ │ │ │ └── indexed_settings_page.dart │ │ │ │ ├── other/ │ │ │ │ │ ├── other_settings_controller.dart │ │ │ │ │ └── other_settings_page.dart │ │ │ │ └── play_settings_page.dart │ │ │ └── sync/ │ │ │ ├── local_sync/ │ │ │ │ ├── device/ │ │ │ │ │ ├── sync_device_controller.dart │ │ │ │ │ └── sync_device_page.dart │ │ │ │ ├── local_sync_controller.dart │ │ │ │ ├── local_sync_page.dart │ │ │ │ └── scan_qr/ │ │ │ │ ├── sync_scan_qr_controller.dart │ │ │ │ └── sync_scan_qr_page.dart │ │ │ ├── remote_sync/ │ │ │ │ ├── room/ │ │ │ │ │ ├── remote_sync_room_controller.dart │ │ │ │ │ └── remote_sync_room_page.dart │ │ │ │ └── webdav/ │ │ │ │ ├── remote_sync_webdav_config_page.dart │ │ │ │ ├── remote_sync_webdav_controller.dart │ │ │ │ ├── remote_sync_webdav_page.dart │ │ │ │ └── webdav_client.dart │ │ │ └── sync_page.dart │ │ ├── requests/ │ │ │ ├── custom_log_interceptor.dart │ │ │ ├── http_client.dart │ │ │ ├── http_error.dart │ │ │ └── sync_client_request.dart │ │ ├── routes/ │ │ │ ├── app_navigation.dart │ │ │ ├── app_pages.dart │ │ │ └── route_path.dart │ │ ├── services/ │ │ │ ├── bilibili_account_service.dart │ │ │ ├── db_service.dart │ │ │ ├── douyin_account_service.dart │ │ │ ├── follow_service.dart │ │ │ ├── local_storage_service.dart │ │ │ ├── signalr_service.dart │ │ │ └── sync_service.dart │ │ └── widgets/ │ │ ├── desktop_refresh_button.dart │ │ ├── filter_button.dart │ │ ├── follow_user_item.dart │ │ ├── keep_alive_wrapper.dart │ │ ├── live_room_card.dart │ │ ├── net_image.dart │ │ ├── none_border_circular_textfield.dart │ │ ├── page_grid_view.dart │ │ ├── page_list_view.dart │ │ ├── rectangular_indicator.dart │ │ ├── settings/ │ │ │ ├── settings_action.dart │ │ │ ├── settings_card.dart │ │ │ ├── settings_menu.dart │ │ │ ├── settings_number.dart │ │ │ └── settings_switch.dart │ │ ├── shadow_card.dart │ │ ├── status/ │ │ │ ├── app_empty_widget.dart │ │ │ ├── app_error_widget.dart │ │ │ └── app_loadding_widget.dart │ │ └── superchat_card.dart │ ├── linux/ │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── flutter/ │ │ │ ├── CMakeLists.txt │ │ │ ├── generated_plugin_registrant.cc │ │ │ ├── generated_plugin_registrant.h │ │ │ └── generated_plugins.cmake │ │ ├── packaging/ │ │ │ └── deb/ │ │ │ └── make_config.yaml │ │ └── runner/ │ │ ├── CMakeLists.txt │ │ ├── main.cc │ │ ├── my_application.cc │ │ └── my_application.h │ ├── macos/ │ │ ├── .gitignore │ │ ├── Flutter/ │ │ │ ├── Flutter-Debug.xcconfig │ │ │ ├── Flutter-Release.xcconfig │ │ │ └── GeneratedPluginRegistrant.swift │ │ ├── Podfile │ │ ├── Runner/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ └── MainMenu.xib │ │ │ ├── Configs/ │ │ │ │ ├── AppInfo.xcconfig │ │ │ │ ├── Debug.xcconfig │ │ │ │ ├── Release.xcconfig │ │ │ │ └── Warnings.xcconfig │ │ │ ├── DebugProfile.entitlements │ │ │ ├── Info.plist │ │ │ ├── MainFlutterWindow.swift │ │ │ └── Release.entitlements │ │ ├── Runner.xcodeproj/ │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace/ │ │ │ │ └── xcshareddata/ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcshareddata/ │ │ │ └── xcschemes/ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── RunnerTests/ │ │ │ └── RunnerTests.swift │ │ └── packaging/ │ │ └── dmg/ │ │ └── make_config.yaml │ ├── pubspec.yaml │ ├── test/ │ │ └── widget_test.dart │ └── windows/ │ ├── .gitignore │ ├── CMakeLists.txt │ ├── flutter/ │ │ ├── CMakeLists.txt │ │ ├── generated_plugin_registrant.cc │ │ ├── generated_plugin_registrant.h │ │ └── generated_plugins.cmake │ ├── packaging/ │ │ └── msix/ │ │ └── make_config.yaml │ └── runner/ │ ├── CMakeLists.txt │ ├── Runner.rc │ ├── flutter_window.cpp │ ├── flutter_window.h │ ├── main.cpp │ ├── resource.h │ ├── runner.exe.manifest │ ├── utils.cpp │ ├── utils.h │ ├── win32_window.cpp │ └── win32_window.h ├── simple_live_console/ │ ├── .gitignore │ ├── .vscode/ │ │ └── launch.json │ ├── CHANGELOG.md │ ├── README.md │ ├── analysis_options.yaml │ ├── bin/ │ │ └── simple_live_console.dart │ ├── pubspec.yaml │ └── test/ │ └── all_live_console_test.dart ├── simple_live_core/ │ ├── .gitignore │ ├── .vscode/ │ │ └── launch.json │ ├── CHANGELOG.md │ ├── README.md │ ├── analysis_options.yaml │ ├── example/ │ │ └── simple_live_core_example.dart │ ├── lib/ │ │ ├── simple_live_core.dart │ │ └── src/ │ │ ├── bilibili_site.dart │ │ ├── common/ │ │ │ ├── binary_writer.dart │ │ │ ├── convert_helper.dart │ │ │ ├── core_error.dart │ │ │ ├── core_log.dart │ │ │ ├── custom_interceptor.dart │ │ │ ├── http_client.dart │ │ │ └── web_socket_util.dart │ │ ├── danmaku/ │ │ │ ├── bilibili_danmaku.dart │ │ │ ├── douyin_danmaku.dart │ │ │ ├── douyu_danmaku.dart │ │ │ ├── huya_danmaku.dart │ │ │ └── proto/ │ │ │ ├── douyin.pb.dart │ │ │ ├── douyin.pbenum.dart │ │ │ ├── douyin.pbjson.dart │ │ │ └── douyin.proto │ │ ├── douyin_site.dart │ │ ├── douyu_site.dart │ │ ├── huya_site.dart │ │ ├── interface/ │ │ │ ├── live_danmaku.dart │ │ │ └── live_site.dart │ │ ├── model/ │ │ │ ├── live_anchor_item.dart │ │ │ ├── live_category.dart │ │ │ ├── live_category_result.dart │ │ │ ├── live_message.dart │ │ │ ├── live_play_quality.dart │ │ │ ├── live_play_url.dart │ │ │ ├── live_room_detail.dart │ │ │ ├── live_room_item.dart │ │ │ ├── live_search_result.dart │ │ │ └── tars/ │ │ │ ├── get_cdn_token_ex_req.dart │ │ │ ├── get_cdn_token_ex_resp.dart │ │ │ ├── get_cdn_token_req.dart │ │ │ ├── get_cdn_token_resp.dart │ │ │ ├── huya_danmaku.dart │ │ │ ├── huya_user_id.dart │ │ │ └── tar2dart.dart │ │ └── scripts/ │ │ ├── douyin_sign.dart │ │ └── douyu_sign.dart │ ├── packages/ │ │ └── tars_dart/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── analysis_options.yaml │ │ ├── lib/ │ │ │ └── tars/ │ │ │ ├── codec/ │ │ │ │ ├── tars_decode_exception.dart │ │ │ │ ├── tars_deep_copyable.dart │ │ │ │ ├── tars_displayer.dart │ │ │ │ ├── tars_encode_exception.dart │ │ │ │ ├── tars_input_stream.dart │ │ │ │ ├── tars_output_stream.dart │ │ │ │ └── tars_struct.dart │ │ │ ├── net/ │ │ │ │ └── base_tars_http.dart │ │ │ └── tup/ │ │ │ ├── basic_class_type_util.dart │ │ │ ├── const.dart │ │ │ ├── object_create_exception.dart │ │ │ ├── request_packet.dart │ │ │ ├── tars_uni_packet.dart │ │ │ ├── tup_response.dart │ │ │ ├── tup_result_exception.dart │ │ │ ├── uni_attribute.dart │ │ │ ├── uni_packet.dart │ │ │ └── write_buffer.dart │ │ └── pubspec.yaml │ ├── pubspec.yaml │ └── test/ │ └── simple_live_core_test.dart └── simple_live_tv_app/ ├── .fvmrc ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android/ │ ├── .gitignore │ ├── app/ │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── debug/ │ │ │ └── AndroidManifest.xml │ │ ├── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin/ │ │ │ │ └── com/ │ │ │ │ └── xycz/ │ │ │ │ └── simple_live_tv/ │ │ │ │ └── MainActivity.kt │ │ │ └── res/ │ │ │ ├── drawable/ │ │ │ │ └── launch_background.xml │ │ │ ├── drawable-v21/ │ │ │ │ └── launch_background.xml │ │ │ ├── mipmap-anydpi-v26/ │ │ │ │ └── ic_banner.xml │ │ │ ├── values/ │ │ │ │ ├── ic_banner_background.xml │ │ │ │ └── styles.xml │ │ │ ├── values-night/ │ │ │ │ └── styles.xml │ │ │ └── xml/ │ │ │ └── network_security_config.xml │ │ └── profile/ │ │ └── AndroidManifest.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ └── settings.gradle.kts ├── assets/ │ ├── lotties/ │ │ ├── empty.json │ │ ├── error.json │ │ └── loadding.json │ └── statement.txt ├── lib/ │ ├── app/ │ │ ├── app_error.dart │ │ ├── app_focus_node.dart │ │ ├── app_style.dart │ │ ├── base_focus_model.dart │ │ ├── constant.dart │ │ ├── controller/ │ │ │ ├── app_settings_controller.dart │ │ │ └── base_controller.dart │ │ ├── event_bus.dart │ │ ├── log.dart │ │ ├── sites.dart │ │ └── utils.dart │ ├── main.dart │ ├── models/ │ │ ├── account/ │ │ │ └── bilibili_user_info_page.dart │ │ ├── db/ │ │ │ ├── follow_user.dart │ │ │ ├── follow_user.g.dart │ │ │ ├── history.dart │ │ │ └── history.g.dart │ │ ├── follow_user_item.dart │ │ └── version_model.dart │ ├── modules/ │ │ ├── account/ │ │ │ └── bilibili/ │ │ │ ├── qr_login_controller.dart │ │ │ └── qr_login_page.dart │ │ ├── agreement/ │ │ │ └── agreement_page.dart │ │ ├── category/ │ │ │ ├── category_controller.dart │ │ │ ├── category_page.dart │ │ │ └── detail/ │ │ │ ├── category_detail_controller.dart │ │ │ └── category_detail_page.dart │ │ ├── follow_user/ │ │ │ └── follow_user_page.dart │ │ ├── history/ │ │ │ ├── history_controller.dart │ │ │ └── history_page.dart │ │ ├── home/ │ │ │ ├── home_controller.dart │ │ │ └── home_page.dart │ │ ├── hot_live/ │ │ │ ├── hot_live_controller.dart │ │ │ └── hot_live_page.dart │ │ ├── live_room/ │ │ │ ├── live_room_controller.dart │ │ │ ├── live_room_page.dart │ │ │ └── player/ │ │ │ ├── player_controller.dart │ │ │ └── player_controls.dart │ │ ├── search/ │ │ │ ├── anchor/ │ │ │ │ ├── search_anchor_controller.dart │ │ │ │ └── search_anchor_page.dart │ │ │ └── room/ │ │ │ ├── search_room_controller.dart │ │ │ └── search_room_page.dart │ │ ├── settings/ │ │ │ ├── settings_controller.dart │ │ │ └── settings_page.dart │ │ └── sync/ │ │ ├── sync_controller.dart │ │ └── sync_page.dart │ ├── requests/ │ │ ├── common_request.dart │ │ ├── custom_log_interceptor.dart │ │ ├── http_client.dart │ │ └── http_error.dart │ ├── routes/ │ │ ├── app_navigation.dart │ │ ├── app_pages.dart │ │ └── route_path.dart │ ├── services/ │ │ ├── bilibili_account_service.dart │ │ ├── db_service.dart │ │ ├── follow_user_service.dart │ │ ├── local_storage_service.dart │ │ ├── signalr_service.dart │ │ └── sync_service.dart │ └── widgets/ │ ├── app_scaffold.dart │ ├── button/ │ │ ├── highlight_button.dart │ │ ├── highlight_list_tile.dart │ │ └── home_big_button.dart │ ├── card/ │ │ ├── anchor_card.dart │ │ └── live_room_card.dart │ ├── highlight_widget.dart │ ├── keep_alive_wrapper.dart │ ├── net_image.dart │ ├── page_grid_view.dart │ ├── rectangular_indicator.dart │ ├── settings_item_widget.dart │ └── status/ │ ├── app_empty_widget.dart │ ├── app_error_widget.dart │ └── app_loadding_widget.dart ├── pubspec.yaml ├── test/ │ └── widget_test.dart └── windows/ ├── .gitignore ├── CMakeLists.txt ├── flutter/ │ ├── CMakeLists.txt │ ├── generated_plugin_registrant.cc │ ├── generated_plugin_registrant.h │ └── generated_plugins.cmake └── runner/ ├── CMakeLists.txt ├── Runner.rc ├── flutter_window.cpp ├── flutter_window.h ├── main.cpp ├── resource.h ├── runner.exe.manifest ├── utils.cpp ├── utils.h ├── win32_window.cpp └── win32_window.h ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug.yml ================================================ name: BUG报告 title: "[BUG] 请填写简短易读的标题" description: "使用过程中遇到了BUG" assignees: xiaoyaocz labels: - "bug" body: - type: checkboxes id: terms attributes: label: 非重复的Issue description: 先去Issues列表中查找下是否存在相似的Issue,如果有了就不要重复发了 options: - label: 已确认没有相似的Issue required: true - type: textarea id: description validations: required: true attributes: label: BUG内容 description: 请详细描述你遇到的问题 - type: textarea id: steps validations: required: true attributes: label: 重现步骤 render: plain text description: 请详细描述重现步骤 placeholder: | 1. xxxx 2. xxxx 3. xxxx - type: textarea id: screenshots attributes: label: 截图或视频 description: 请上传BUG截图、或视频 - type: textarea id: logs attributes: label: 日志 description: 请上传日志文件 placeholder: | 可以在[其他设置]-[开启日志记录]后获取日志文件 - type: input id: version attributes: label: 版本号 description: 请填写你使用的APP版本号 placeholder: ex. 1.0.1 validations: required: true - type: dropdown id: release-type validations: required: true attributes: label: 使用版本 description: 使用的是什么版本,从哪里下载的 options: - 正式版(Releases) - 开发版(Actions) default: 0 - type: dropdown id: platform validations: required: true attributes: label: 运行平台 description: 选择你当前运行应用的平台 multiple: false options: - Windows - macOS - Linux - Android - iOS - Android TV - type: input id: os-version attributes: label: 操作系统信息 description: 请填写你的操作系统信息版本 placeholder: ex. Windows 10 21H1 / MIUI 15 Android 12 validations: required: true - type: input id: device attributes: label: 设备信息 description: 请填写你的设备信息 placeholder: ex. PC / iPhone 12 Pro Max validations: required: true - type: textarea id: remark attributes: label: 备注 description: 其他信息 ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false ================================================ FILE: .github/ISSUE_TEMPLATE/feature.yml ================================================ name: 功能请求 title: "[Feature] 请填写简短易读的标题" description: "请求开发新的功能/优化某项功能" assignees: xiaoyaocz labels: - "enhancement" body: - type: markdown attributes: value: | 你的Issue大概率会搁置很久,除非是那种我能随手解决的。 暂时不会添加新的平台支持(因为我自己用不上)。如果你有开发能力,建议的自行开发后提交个PR。 - type: checkboxes id: terms attributes: label: 非重复的Issue description: 先去Issues列表中查找下是否存在相似的Issue,如果有了就不要重复发了 options: - label: 已确认没有相似的Issue required: true - type: textarea id: description validations: required: true attributes: label: 功能描述 description: 请填写功能描述,如果你有多个建议、请求,请分开提交Issue - type: checkboxes id: platform attributes: label: 平台 description: 这个功能针对什么平台 options: - label: Android - label: iOS - label: MacOS - label: Windows - label: Linux - label: Android TV - type: textarea id: additional attributes: label: 附加信息 description: 可以附加相关截图、视频或链接(好让我知道要我抄哪个APP) ================================================ FILE: .github/workflows/publish_app_dev.yaml ================================================ name: app-build-action-dev on: workflow_dispatch: push: tags: - "dev_v*" jobs: # 打包Android、iOS、Mac build-mac-ios-android: runs-on: macos-latest permissions: contents: write steps: # 签出代码 - uses: actions/checkout@v4 with: ref: dev # APK签名设置 - name: Download Android keystore id: android_keystore uses: timheuer/base64-to-file@v1.2 with: fileName: keystore.jks encodedString: ${{ secrets.KEYSTORE_BASE64 }} - name: Create key.properties run: | echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > simple_live_app/android/key.properties echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> simple_live_app/android/key.properties echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> simple_live_app/android/key.properties echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> simple_live_app/android/key.properties # 设置JAVA环境 - uses: actions/setup-java@v4 with: distribution: "zulu" java-version: "17" cache: "gradle" # 设置Flutter - name: Flutter action uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true # 打开MAC Desktop支持 - name: Enable Flutter Desktop run: flutter config --enable-macos-desktop # 更新Flutter的packages - name: Restore packages run: | cd simple_live_app flutter pub get # 安装appdmg npm install -g appdmg - name: Install appdmg run: npm install -g appdmg # 设置flutter_distributor环境 - name: Install flutter_distributor run: dart pub global activate flutter_distributor # 打包APK - name: Build APK run: | cd simple_live_app flutter build apk --release --split-per-abi #上传Artifacts - name: Upload APK to Artifacts uses: actions/upload-artifact@v4 with: name: android path: | simple_live_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk simple_live_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk simple_live_app/build/app/outputs/flutter-apk/app-x86_64-release.apk #打包iOS - name: Build IPA run: | cd simple_live_app flutter build ios --release --no-codesign #创建未签名ipa - name: Create IPA run: | cd simple_live_app mkdir build/ios/iphoneos/Payload cp -R build/ios/iphoneos/Runner.app build/ios/iphoneos/Payload/Runner.app cd build/ios/iphoneos/ zip -q -r ios_no_sign.ipa Payload cd ../../.. # 上传IPA至Artifacts - name: Upload IPA to Artifacts uses: actions/upload-artifact@v4 with: name: ios path: | simple_live_app/build/ios/iphoneos/ios_no_sign.ipa # 打包MAC - name: Build MacOS run: | cd simple_live_app flutter_distributor package --platform macos --targets dmg,zip --skip-clean # 上传MAC至Artifacts - name: Upload MacOS to Artifacts uses: actions/upload-artifact@v4 with: name: mac path: | simple_live_app/build/dist/*/*.dmg simple_live_app/build/dist/*/*.zip #完成 - run: echo "🍏 This job's status is ${{ job.status }}." # 打包Linux build-linux: runs-on: ubuntu-22.04 permissions: contents: write steps: # 签出代码 - uses: actions/checkout@v4 with: ref: dev # 设置Flutter环境 - name: Setup Flutter uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true # 安装依赖 - name: Update apt-get run: sudo apt-get update - name: Install Dependencies run: sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libasound2-dev libmpv-dev mpv # 打开Linux Desktop支持 - name: Enable Flutter Desktop run: flutter config --enable-linux-desktop # 更新Flutter的packages - name: Restore Packages run: | cd simple_live_app flutter pub get # 设置flutter_distributor环境 - name: Install flutter_distributor run: dart pub global activate flutter_distributor # build Linux ZIP\DMG - name: Build Linux run: | cd simple_live_app flutter_distributor package --platform linux --targets deb,zip --skip-clean # 上传Linux包至Artifacts - name: Upload Linux APP to Artifacts uses: actions/upload-artifact@v4 with: name: linux path: | simple_live_app/build/dist/*/*.deb simple_live_app/build/dist/*/*.zip #完成 - run: echo "🍏 Linux job's status is ${{ job.status }}." # 打包Windows build-windows: runs-on: windows-latest permissions: contents: write steps: # 签出代码 - uses: actions/checkout@v4 with: ref: dev # 设置Flutter环境 - name: Setup Flutter uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true - name: Enable Flutter Desktop run: flutter config --enable-windows-desktop - name: Restore Packages run: | cd simple_live_app flutter pub get # 设置flutter_distributor环境 - name: Install flutter_distributor run: dart pub global activate flutter_distributor # build Windows ZIP\MSIX - name: Build Windows run: | cd simple_live_app flutter_distributor package --platform windows --targets msix,zip --skip-clean # 上传Windows至Artifacts - name: Upload Windows APP to Artifacts uses: actions/upload-artifact@v4 with: name: windows path: | simple_live_app/build/dist/*/*.msix simple_live_app/build/dist/*/*.zip #完成 - run: echo "🍏 Windows job's status is ${{ job.status }}." ================================================ FILE: .github/workflows/publish_app_release.yml ================================================ name: app-build-action #推送Tag时触发 on: push: tags: - "v*" jobs: build-mac-ios-android: runs-on: macos-latest permissions: contents: write steps: #签出代码 - uses: actions/checkout@v4 with: ref: master #APK签名设置 - name: Download Android keystore id: android_keystore uses: timheuer/base64-to-file@v1.2 with: fileName: keystore.jks encodedString: ${{ secrets.KEYSTORE_BASE64 }} - name: Create key.properties run: | echo "storeFile=${{ steps.android_keystore.outputs.filePath }}" > simple_live_app/android/key.properties echo "storePassword=${{ secrets.STORE_PASSWORD }}" >> simple_live_app/android/key.properties echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> simple_live_app/android/key.properties echo "keyAlias=${{ secrets.KEY_ALIAS }}" >> simple_live_app/android/key.properties #设置JAVA环境 - uses: actions/setup-java@v4 with: distribution: "zulu" java-version: "17" cache: "gradle" #设置Flutter - name: Flutter action uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true # 打开MAC Desktop支持 - name: Enable Flutter Desktop run: flutter config --enable-macos-desktop #更新Flutter的packages - name: Restore packages run: | cd simple_live_app flutter pub get # 安装appdmg npm install -g appdmg - name: Install appdmg run: npm install -g appdmg # 设置flutter_distributor环境 - name: Install flutter_distributor run: dart pub global activate flutter_distributor #打包APK - name: Build APK run: | cd simple_live_app flutter build apk --release --split-per-abi #上传APK至Artifacts - name: Upload APK to Artifacts uses: actions/upload-artifact@v4 with: name: android path: | simple_live_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk simple_live_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk simple_live_app/build/app/outputs/flutter-apk/app-x86_64-release.apk #打包iOS - name: Build IPA run: | cd simple_live_app flutter build ios --release --no-codesign #创建未签名ipa - name: Create IPA run: | cd simple_live_app mkdir build/ios/iphoneos/Payload cp -R build/ios/iphoneos/Runner.app build/ios/iphoneos/Payload/Runner.app cd build/ios/iphoneos/ zip -q -r ios_no_sign.ipa Payload cd ../../.. #上传IPA至Artifacts - name: Upload IPA to Artifacts uses: actions/upload-artifact@v4 with: name: ios path: | simple_live_app/build/ios/iphoneos/ios_no_sign.ipa # 打包MAC - name: Build MacOS run: | cd simple_live_app flutter_distributor package --platform macos --targets dmg,zip --skip-clean # 上传MAC至Artifacts - name: Upload MacOS to Artifacts uses: actions/upload-artifact@v4 with: name: mac path: | simple_live_app/build/dist/*/*.dmg simple_live_app/build/dist/*/*.zip #获取版本信息(自动从 Git Tag 提取) - name: Get version from tag id: version run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - name: Echo version run: echo "${{ steps.version.outputs.VERSION }}" #上传至Release - name: Upload Release uses: softprops/action-gh-release@v1 with: name: "${{ steps.version.outputs.VERSION }}" generate_release_notes: true prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'alpha') }} token: ${{ secrets.TOKEN }} files: | simple_live_app/build/app/outputs/flutter-apk/app-x86_64-release.apk simple_live_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk simple_live_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk simple_live_app/build/ios/iphoneos/ios_no_sign.ipa simple_live_app/build/dist/*/*.dmg simple_live_app/build/dist/*/*.zip #完成 - run: echo "🍏 This job's status is ${{ job.status }}." # 打包Linux build-linux: runs-on: ubuntu-22.04 permissions: contents: write steps: # 签出代码 - uses: actions/checkout@v4 with: ref: master # 设置Flutter环境 - name: Setup Flutter uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true # 安装依赖 - name: Update apt-get run: sudo apt-get update - name: Install Dependencies run: sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libasound2-dev libmpv-dev mpv # 打开Linux Desktop支持 - name: Enable Flutter Desktop run: flutter config --enable-linux-desktop # 更新Flutter的packages - name: Restore Packages run: | cd simple_live_app flutter pub get # 设置flutter_distributor环境 - name: Install flutter_distributor run: dart pub global activate flutter_distributor # build Linux ZIP\DMG - name: Build Linux run: | cd simple_live_app flutter_distributor package --platform linux --targets deb,zip --skip-clean # 上传Linux包至Artifacts - name: Upload Linux APP to Artifacts uses: actions/upload-artifact@v4 with: name: linux path: | simple_live_app/build/dist/*/*.deb simple_live_app/build/dist/*/*.zip #获取版本信息(自动从 Git Tag 提取) - name: Get version from tag id: version run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - name: Echo version run: echo "${{ steps.version.outputs.VERSION }}" #上传至Release - name: Upload Release uses: softprops/action-gh-release@v1 with: name: "${{ steps.version.outputs.VERSION }}" generate_release_notes: true prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'alpha') }} token: ${{ secrets.TOKEN }} files: | simple_live_app/build/dist/*/*.deb simple_live_app/build/dist/*/*.zip #完成 - run: echo "🍏 Linux job's status is ${{ job.status }}." # 打包Windows build-windows: runs-on: windows-latest permissions: contents: write steps: # 签出代码 - uses: actions/checkout@v4 with: ref: master # 设置Flutter环境 - name: Setup Flutter uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true - name: Enable Flutter Desktop run: flutter config --enable-windows-desktop - name: Restore Packages run: | cd simple_live_app flutter pub get # 设置flutter_distributor环境 - name: Install flutter_distributor run: dart pub global activate flutter_distributor # build Windows ZIP\MSIX - name: Build Windows run: | cd simple_live_app flutter_distributor package --platform windows --targets msix,zip --skip-clean # 上传Windows至Artifacts - name: Upload Windows APP to Artifacts uses: actions/upload-artifact@v4 with: name: windows path: | simple_live_app/build/dist/*/*.msix simple_live_app/build/dist/*/*.zip #获取版本信息(自动从 Git Tag 提取) - name: Get version from tag id: version shell: bash run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT - name: Echo version run: echo "${{ steps.version.outputs.VERSION }}" #上传至Release - name: Upload Release uses: softprops/action-gh-release@v1 with: name: "${{ steps.version.outputs.VERSION }}" generate_release_notes: true prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'alpha') }} token: ${{ secrets.TOKEN }} files: | simple_live_app/build/dist/*/*.msix simple_live_app/build/dist/*/*.zip #完成 - run: echo "🍏 Windows job's status is ${{ job.status }}." ================================================ FILE: .github/workflows/publish_tv_app_dev.yaml ================================================ name: app-build-action #推送Tag时触发 on: push: tags: - "dev_tv_v*" jobs: build-tv: runs-on: macos-latest permissions: contents: write steps: #签出代码 - uses: actions/checkout@v4 with: ref: dev #APK签名设置 - name: Download Android keystore id: android_tv_keystore uses: timheuer/base64-to-file@v1.2 with: fileName: keystore.jks encodedString: ${{ secrets.TV_KEYSTORE_BASE64 }} - name: Create key.properties run: | echo "storeFile=${{ steps.android_tv_keystore.outputs.filePath }}" > simple_live_tv_app/android/key.properties echo "storePassword=${{ secrets.TV_STORE_PASSWORD }}" >> simple_live_tv_app/android/key.properties echo "keyPassword=${{ secrets.TV_KEY_PASSWORD }}" >> simple_live_tv_app/android/key.properties echo "keyAlias=${{ secrets.TV_KEY_ALIAS }}" >> simple_live_tv_app/android/key.properties # 设置JAVA环境 - uses: actions/setup-java@v4 with: distribution: "zulu" java-version: "17" cache: "gradle" #设置Flutter - name: Flutter action uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true #更新Flutter的packages - name: Restore packages run: | cd simple_live_tv_app flutter pub get #打包APK - name: Build APK run: | cd simple_live_tv_app flutter build apk --release --split-per-abi #上传APK至Artifacts - name: Upload APK to Artifacts uses: actions/upload-artifact@v4 with: name: android_tv path: | simple_live_tv_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk simple_live_tv_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk simple_live_tv_app/build/app/outputs/flutter-apk/app-x86_64-release.apk #完成 - run: echo "🍏 This job's status is ${{ job.status }}." ================================================ FILE: .github/workflows/publish_tv_app_release.yaml ================================================ name: app-build-action #推送Tag时触发 on: push: tags: - "tv_*" jobs: build-tv: runs-on: macos-latest permissions: contents: write steps: #签出代码 - uses: actions/checkout@v4 with: ref: master #APK签名设置 - name: Download Android keystore id: android_tv_keystore uses: timheuer/base64-to-file@v1.2 with: fileName: keystore.jks encodedString: ${{ secrets.TV_KEYSTORE_BASE64 }} - name: Create key.properties run: | echo "storeFile=${{ steps.android_tv_keystore.outputs.filePath }}" > simple_live_tv_app/android/key.properties echo "storePassword=${{ secrets.TV_STORE_PASSWORD }}" >> simple_live_tv_app/android/key.properties echo "keyPassword=${{ secrets.TV_KEY_PASSWORD }}" >> simple_live_tv_app/android/key.properties echo "keyAlias=${{ secrets.TV_KEY_ALIAS }}" >> simple_live_tv_app/android/key.properties # 设置JAVA环境 - uses: actions/setup-java@v4 with: distribution: "zulu" java-version: "17" cache: "gradle" #设置Flutter - name: Flutter action uses: subosito/flutter-action@v2 with: flutter-version: "3.38.x" cache: true #更新Flutter的packages - name: Restore packages run: | cd simple_live_tv_app flutter pub get #打包APK - name: Build APK run: | cd simple_live_tv_app flutter build apk --release --split-per-abi #上传APK至Artifacts - name: Upload APK to Artifacts uses: actions/upload-artifact@v4 with: name: android_tv path: | simple_live_tv_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk simple_live_tv_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk simple_live_tv_app/build/app/outputs/flutter-apk/app-x86_64-release.apk #读取版本信息 - name: Read version id: version uses: juliangruber/read-file-action@v1 with: path: assets/tv_app_version.json - name: Echo version run: echo "${{ fromJson(steps.version.outputs.content).version }}" - name: Echo version content run: echo "${{ fromJson(steps.version.outputs.content).version_desc }}" #上传至Release - name: Upload Release uses: softprops/action-gh-release@v1 with: name: "${{ fromJson(steps.version.outputs.content).version }}" body: "# Android TV \n${{ fromJson(steps.version.outputs.content).version_desc }}" prerelease: ${{ fromJson(steps.version.outputs.content).prerelease }} token: ${{ secrets.TOKEN }} files: | simple_live_tv_app/build/app/outputs/flutter-apk/app-x86_64-release.apk simple_live_tv_app/build/app/outputs/flutter-apk/app-arm64-v8a-release.apk simple_live_tv_app/build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk #完成 - run: echo "🍏 This job's status is ${{ job.status }}." ================================================ FILE: .gitignore ================================================ simple_live_app/.vscode/settings.json simple_live_tv_app/.vscode/settings.json # macOS Spotlight Search index file *.DS_Store ================================================ FILE: .vscode/settings.json ================================================ { "cmake.ignoreCMakeListsMissing": true } ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 2023-2025 xiaoyaocz This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Simple Live Copyright (C) 2023-2025 xiaoyaocz This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ================================================ FILE: README.md ================================================ > ### ⚠ 本项目不提供Release安装包,请自行编译后运行测试。

Simple Live logo

Simple Live

简简单单的看直播

![浅色模式](/assets/screenshot_light.jpg) ![深色模式](/assets/screenshot_dark.jpg) ## 支持直播平台: - 虎牙直播 - 斗鱼直播 - 哔哩哔哩直播 - 抖音直播 ## APP支持平台 - [x] Android - [x] iOS - [x] Windows `BETA` - [x] MacOS `BETA` - [x] Linux `BETA` - [x] Android TV `BETA` ## 项目结构 - `simple_live_core` 项目核心库,实现获取各个网站的信息及弹幕。 - `simple_live_console` 基于simple_live_core的控制台程序。 - `simple_live_app` 基于核心库实现的Flutter APP客户端。 - `simple_live_tv_app` 基于核心库实现的Flutter Android TV客户端。 ## 环境 Flutter : `3.38` ## 参考及引用 [AllLive](https://github.com/xiaoyaocz/AllLive) `本项目的C#版,有兴趣可以看看` [dart_tars_protocol](https://github.com/xiaoyaocz/dart_tars_protocol.git) [wbt5/real-url](https://github.com/wbt5/real-url) [lovelyyoshino/Bilibili-Live-API](https://github.com/lovelyyoshino/Bilibili-Live-API/blob/master/API.WebSocket.md) [IsoaSFlus/danmaku](https://github.com/IsoaSFlus/danmaku) [BacooTang/huya-danmu](https://github.com/BacooTang/huya-danmu) [TarsCloud/Tars](https://github.com/TarsCloud/Tars) [YunzhiYike/douyin-live](https://github.com/YunzhiYike/douyin-live) [5ime/Tiktok_Signature](https://github.com/5ime/Tiktok_Signature) ## 声明 本项目的所有功能都是基于互联网上公开的资料开发,无任何破解、逆向工程等行为。 本项目仅用于学习交流编程技术,严禁将本项目用于商业目的。如有任何商业行为,均与本项目无关。 如果本项目存在侵犯您的合法权益的情况,请及时与开发者联系,开发者将会及时删除有关内容。 ## Star History Star History Chart ================================================ FILE: assets/app_version.json ================================================ { "version": "1.11.1", "version_num": 11101, "version_desc": "- 版本更新", "prerelease": false, "download_url": "https://github.com/xiaoyaocz/dart_simple_live/releases" } ================================================ FILE: assets/play_config.json ================================================ { "huya": { "user_agent": "HYSDK(Windows, 30000002)_APP(pc_exe&6080100&official)_SDK(trans&2.23.0.4969)" } } ================================================ FILE: assets/tv_app_version.json ================================================ { "version": "1.3.5", "version_num": 10305, "version_desc": "- 修复虎牙播放中断 #723 @SlotSun\n- 修复哔哩哔哩加载失败", "prerelease":true, "download_url": "https://github.com/xiaoyaocz/dart_simple_live/releases" } ================================================ FILE: simple_live_app/.fvmrc ================================================ { "flutter": "3.38.3" } ================================================ FILE: simple_live_app/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .build/ .buildlog/ .history .svn/ .swiftpm/ migrate_working_dir/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Symbolication related app.*.symbols # Obfuscation related app.*.map.json # Android Studio will place build artifacts here /android/app/debug /android/app/profile /android/app/release /ios/Podfile.lock pubspec.lock .fvm/ /android/app/.cxx ================================================ FILE: simple_live_app/.metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: "19074d12f7eaf6a8180cd4036a430c1d76de904e" channel: "stable" project_type: app # Tracks metadata for the flutter migrate command migration: platforms: - platform: root create_revision: 19074d12f7eaf6a8180cd4036a430c1d76de904e base_revision: 19074d12f7eaf6a8180cd4036a430c1d76de904e - platform: linux create_revision: 19074d12f7eaf6a8180cd4036a430c1d76de904e base_revision: 19074d12f7eaf6a8180cd4036a430c1d76de904e # User provided section # List of Local paths (relative to this file) that should be # ignored by the migrate tool. # # Files that are not part of the templates will be ignored by default. unmanaged_files: - 'lib/main.dart' - 'ios/Runner.xcodeproj/project.pbxproj' ================================================ FILE: simple_live_app/README.md ================================================ # simple_live_app 基于核心库实现的Flutter APP客户端。 ## TODO - [ ] 支持桌面平台 - [ ] iOS播放问题 - [ ] 全屏、非全屏弹幕样式分离 - [ ] 重写直播间 ================================================ FILE: simple_live_app/analysis_options.yaml ================================================ # This file configures the analyzer, which statically analyzes Dart code to # check for errors, warnings, and lints. # # The issues identified by the analyzer are surfaced in the UI of Dart-enabled # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be # invoked from the command line by running `flutter analyze`. # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` # included above or to enable additional rules. A list of all available lints # and their documentation is published at # https://dart-lang.github.io/linter/lints/index.html. # # Instead of disabling a lint rule for the entire project in the # section below, it can also be suppressed for a single line of code # or a specific dart file by using the `// ignore: name_of_lint` and # `// ignore_for_file: name_of_lint` syntax on the line or in the file # producing the lint. rules: # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options ================================================ FILE: simple_live_app/android/.gitignore ================================================ gradle-wrapper.jar /.gradle /captures/ /gradlew /gradlew.bat /local.properties GeneratedPluginRegistrant.java .cxx/ # Remember to never publicly share your keystore. # See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks ================================================ FILE: simple_live_app/android/app/build.gradle.kts ================================================ import java.util.Properties import java.io.FileInputStream plugins { id("com.android.application") id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") } val keystoreProperties = Properties() val keystorePropertiesFile = rootProject.file("key.properties") if (keystorePropertiesFile.exists()) { keystoreProperties.load(FileInputStream(keystorePropertiesFile)) } android { namespace = "com.xycz.simple_live" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.xycz.simple_live" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName } signingConfigs { create("release") { keyAlias = keystoreProperties["keyAlias"] as String keyPassword = keystoreProperties["keyPassword"] as String storeFile = keystoreProperties["storeFile"]?.let { file(it) } storePassword = keystoreProperties["storePassword"] as String isV1SigningEnabled = true isV2SigningEnabled = true } } buildTypes { release { // Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.getByName("release") isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with automatically generated optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } } flutter { source = "../.." } ================================================ FILE: simple_live_app/android/app/proguard-rules.pro ================================================ #Flutter Wrapper -keep class io.flutter.app.** { *; } -keep class io.flutter.plugin.** { *; } -keep class io.flutter.util.** { *; } -keep class io.flutter.view.** { *; } -keep class io.flutter.** { *; } -keep class io.flutter.plugins.** { *; } -keep class de.prosiebensat1digital.** { *; } -dontwarn io.flutter.embedding.** -ignorewarnings ================================================ FILE: simple_live_app/android/app/src/debug/AndroidManifest.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/kotlin/com/xycz/simple_live/MainActivity.kt ================================================ package com.xycz.simple_live import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() ================================================ FILE: simple_live_app/android/app/src/main/res/drawable/launch_background.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/res/drawable-v21/launch_background.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/res/values/ic_launcher_background.xml ================================================ #FFFFFF ================================================ FILE: simple_live_app/android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/res/values-night/styles.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/main/res/xml/network_security_config.xml ================================================ ================================================ FILE: simple_live_app/android/app/src/profile/AndroidManifest.xml ================================================ ================================================ FILE: simple_live_app/android/build/reports/problems/problems-report.html ================================================ Gradle Configuration Cache
Loading...
================================================ FILE: simple_live_app/android/build.gradle.kts ================================================ allprojects { repositories { google() mavenCentral() } } val newBuildDir: Directory = rootProject.layout.buildDirectory .dir("../../build") .get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) project.layout.buildDirectory.value(newSubprojectBuildDir) } subprojects { project.evaluationDependsOn(":app") } tasks.register("clean") { delete(rootProject.layout.buildDirectory) } ================================================ FILE: simple_live_app/android/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip ================================================ FILE: simple_live_app/android/gradle.properties ================================================ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true ================================================ FILE: simple_live_app/android/settings.gradle.kts ================================================ pluginManagement { val flutterSdkPath = run { val properties = java.util.Properties() file("local.properties").inputStream().use { properties.load(it) } val flutterSdkPath = properties.getProperty("flutter.sdk") require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } flutterSdkPath } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") repositories { google() mavenCentral() gradlePluginPortal() } } plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.9.1" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false } include(":app") ================================================ FILE: simple_live_app/assets/lotties/empty.json ================================================ {"v":"4.7.0","fr":25,"ip":0,"op":50,"w":120,"h":120,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ruoi","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p967_0p167_0p033"],"t":35,"s":[100],"e":[0]},{"t":49}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0,"y":0},"n":"0p833_0p833_0_0","t":0,"s":[57.361,61.016,0],"e":[57.699,41.796,0],"to":[-4.67500305175781,-4.12800598144531,0],"ti":[-13.9099960327148,5.27300262451172,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10.219,"s":[57.699,41.796,0],"e":[79.084,33.982,0],"to":[12.8159942626953,-4.85800170898438,0],"ti":[-4.54498291015625,3.73400115966797,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.445,"s":[79.084,33.982,0],"e":[59.691,9.121,0],"to":[6.61601257324219,-5.43799591064453,0],"ti":[20.0290069580078,1.20700073242188,0]},{"t":35}]},"a":{"a":0,"k":[60.531,10.945,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.994,0],[0,-0.994],[0.995,0],[0,0.994]],"o":[[0.995,0],[0,0.994],[-0.994,0],[0,-0.994]],"v":[[-0.001,-1.801],[1.801,-0.001],[-0.001,1.801],[-1.801,-0.001]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[62.4,13.144],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.422,0],[0,-1.422],[1.421,0],[0,1.422]],"o":[[1.421,0],[0,1.422],[-1.422,0],[0,-1.422]],"v":[[0.001,-2.574],[2.574,0],[0.001,2.574],[-2.574,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[64.145,9.606],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.996,0],[0,-1.996],[1.996,0],[0,1.996]],"o":[[1.996,0],[0,1.996],[-1.996,0],[0,-1.996]],"v":[[0,-3.614],[3.614,0],[0,3.614],[-3.614,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[57.957,10.552],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"tr","p":{"a":0,"k":[60.531,10.941],"ix":2},"a":{"a":0,"k":[60.531,10.941],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"ruoi","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p967_0p167_0p033"],"t":35,"s":[100],"e":[0]},{"t":49}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[-0.75,-0.75,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-13.91,5.273],[-4.545,3.734],[20.029,1.207]],"o":[[-4.675,-4.128],[12.816,-4.858],[6.616,-5.438],[0,0]],"v":[[-7.383,24.76],[-7.046,5.54],[14.34,-2.273],[-3.178,-24.76]],"c":false}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.34901960784313724,0.3686274509803922,0.4,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":2,"lj":2,"d":[{"n":"d","nm":"dash","v":{"a":0,"k":2.028}},{"n":"g","nm":"gap","v":{"a":0,"k":2.028}},{"n":"o","nm":"offset","v":{"a":0,"k":0}}],"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[67.87,37.631],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.953]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p953_0p167_0p033"],"t":0,"s":[0],"e":[100]},{"t":35}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"im_emptyBox Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-0.001,-16.607],[-32.143,-0.002],[-0.001,16.607],[32.144,-0.002]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8,0.82,0.851,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,55.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.856,-23.249],[0,-16.605],[-12.857,-23.249],[-45,-6.641],[-32.144,0.001],[-45,6.645],[-12.857,23.249],[0,16.609],[12.856,23.249],[45,6.645],[32.143,0.001],[45,-6.641]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.9372549019607843,0.9372549019607843,0.9372549019607843,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,55.748],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.072,24.171],[16.072,11.312],[16.072,-24.171],[-16.072,-24.171]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.9529411764705882,0.9529411764705882,0.9529411764705882,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[76.072,83.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-32.143,-24.171],[-32.143,11.311],[-0.001,24.171],[32.144,11.311],[32.144,-24.171]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8,0.82,0.851,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,83.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"tr","p":{"a":0,"k":[60,60.186],"ix":2},"a":{"a":0,"k":[60,60.186],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"box","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1}]} ================================================ FILE: simple_live_app/assets/lotties/error.json ================================================ {"v":"5.8.1","fr":29.9700012207031,"ip":0,"op":301.000012259981,"w":1080,"h":900,"nm":"Composition 1","ddd":0,"assets":[{"id":"comp_0","nm":"Nuage","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-22,-239],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[544.675,315.475,0],"ix":2,"l":2},"a":{"a":0,"k":[-54.5,-226.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[31,31],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-54.5,-226.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[31,31],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-54.5,-226.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-26,-216],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_1","nm":"éolienne","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Hélices","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.137],"y":[1]},"o":{"x":[0.567],"y":[0]},"t":1,"s":[0]},{"t":300.00001221925,"s":[1440]}],"ix":10},"p":{"a":0,"k":[800,440,0],"ix":2,"l":2},"a":{"a":0,"k":[800,440,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Socle eolienne","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[264.75,-95],[257,-95],[242,252],[288,251]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_2","nm":"Hélices","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-239.6,"ix":10},"p":{"a":0,"k":[803,442,0],"ix":2,"l":2},"a":{"a":0,"k":[263,-98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-122.747,"ix":10},"p":{"a":0,"k":[803,442,0],"ix":2,"l":2},"a":{"a":0,"k":[263,-98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[803,442,0],"ix":2,"l":2},"a":{"a":0,"k":[263,-98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[800.5,439.5,0],"ix":2,"l":2},"a":{"a":0,"k":[266.5,-94.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[27,27],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[266.5,-94.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_3","nm":"plot base","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[541,387.5,0],"ix":2,"l":2},"a":{"a":0,"k":[1,-152.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-223],[-13,-223],[-52,-82],[54,-82]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,502,0],"ix":2,"l":2},"a":{"a":0,"k":[0,-38,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[58,-56],[-59,-56],[-70,-20],[70,-20]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[539.75,606.25,0],"ix":2,"l":2},"a":{"a":0,"k":[-0.25,66.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[256.5,28.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.7647058823529411,0.3215686274509804,0.23137254901960785,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-0.25,66.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,572,0],"ix":2,"l":2},"a":{"a":0,"k":[0,32,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[78,3],[-76,3],[-93,60],[93,61]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_4","nm":"Tree","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-171.5,-79.5],[-152.5,-45]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980451995,0.84313731474,0.84313731474,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-154.5,-23.5],[-137.5,-48.5]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980451995,0.84313731474,0.84313731474,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[386,620,0],"ix":2,"l":2},"a":{"a":0,"k":[-154,80,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-154,256],[-154,-96]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.844306078144,0.844306078144,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[384,475,0],"ix":2,"l":2},"a":{"a":0,"k":[-156,-65,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,222],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":62,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019667682,0.949019667682,0.949019667682,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-156,-65],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_5","nm":"ground","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[515,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[662,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[817,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[78,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[752,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[89,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[102,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Nuage","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":234,"s":[100]},{"t":299.00001217852,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.284,"y":1},"o":{"x":0.387,"y":0},"t":0,"s":[704,380,0],"to":[-36.667,0,0],"ti":[36.667,0,0]},{"t":299.00001217852,"s":[484,380,0]}],"ix":2,"l":2},"a":{"a":0,"k":[514,308,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],"o":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],"v":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.83137254902,0.821591725069,0.821591725069,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"éolienne","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[804,796,0],"ix":2,"l":2},"a":{"a":0,"k":[804,796,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"plot base","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7.368,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14.736,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":22.264,"s":[4]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":29.633,"s":[-2]},{"t":37.0000015070409,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[540,792,0],"to":[0,-2.667,0],"ti":[0,2,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":7.368,"s":[540,776,0],"to":[0,-2,0],"ti":[0,-1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":14.736,"s":[540,780,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":22.264,"s":[540,784,0],"to":[0,1.333,0],"ti":[0,-2,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":29.633,"s":[540,788,0],"to":[0,2,0],"ti":[0,-1.333,0]},{"t":37.0000015070409,"s":[540,796,0]}],"ix":2,"l":2},"a":{"a":0,"k":[540,616,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"éolienne","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[670,796,0],"ix":2,"l":2},"a":{"a":0,"k":[804,796,0],"ix":1,"l":2},"s":{"a":0,"k":[63,63,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Tree","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,790,0],"ix":2,"l":2},"a":{"a":0,"k":[384,790,0],"ix":1,"l":2},"s":{"a":0,"k":[82,82,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Tree","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[540,540,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Arbuste","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[68,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],"o":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],"v":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"ground","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[540,540,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"Nuage","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[100]},{"t":299.00001217852,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[193,606,0],"to":[56.5,0,0],"ti":[-56.5,0,0]},{"t":299.00001217852,"s":[532,606,0]}],"ix":2,"l":2},"a":{"a":0,"k":[514,308,0],"ix":1,"l":2},"s":{"a":0,"k":[60,60,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Calque de forme 6","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[572,712,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[784,628],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.909803921569,0.909803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-36,-234],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Calque de forme 5","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,716,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[728,728],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.976470588235,0.976470588235,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8,-140],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":1,"nm":"Blanc uni 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[540,540,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"sw":1080,"sh":900,"ip":0,"op":630.000025660426,"st":0,"bm":0}],"markers":[]} ================================================ FILE: simple_live_app/assets/lotties/loadding.json ================================================ { "v": "5.5.8", "fr": 50, "ip": 0, "op": 147, "w": 800, "h": 600, "nm": "Paperplane", "ddd": 0, "assets": [ { "id": "comp_0", "layers": [ { "ddd": 0, "ind": 1, "ty": 4, "nm": "planete Outlines - Group 4", "sr": 1, "ks": { "o": { "a": 1, "k": [ { "i": { "x": [ 0.833 ], "y": [ 0.833 ] }, "o": { "x": [ 0.167 ], "y": [ 0.167 ] }, "t": 0, "s": [ 0 ] }, { "i": { "x": [ 0.833 ], "y": [ 0.833 ] }, "o": { "x": [ 0.167 ], "y": [ 0.167 ] }, "t": 38, "s": [ 50 ] }, { "i": { "x": [ 0.833 ], "y": [ 0.833 ] }, "o": { "x": [ 0.167 ], "y": [ 0.167 ] }, "t": 88, "s": [ 50 ] }, { "t": 120, "s": [ 0 ] } ], "ix": 11 }, "r": { "a": 0, "k": 0, "ix": 10 }, "p": { "a": 1, "k": [ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 0, "s": [ 468.336, 323.378, 0 ], "to": [ -29, 0, 0 ], "ti": [ 29, 0, 0 ] }, { "t": 102, "s": [ 294.336, 323.378, 0 ] } ], "ix": 2 }, "a": { "a": 0, "k": [ 453.672, 304.756, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50, 100 ], "ix": 6 } }, "ao": 0, "shapes": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 6.742, 0 ], [ 0.741, -0.14 ], [ 0, 0.074 ], [ 13.484, 0 ], [ 1.669, -0.361 ], [ 19.79, 0 ], [ 3.317, -19.082 ], [ 2.691, 0 ], [ 0, -13.484 ], [ -0.048, -0.629 ], [ 2.405, 0 ], [ 0, -6.742 ], [ -6.742, 0 ], [ 0, 0 ], [ 0, 6.743 ] ], "o": [ [ -0.781, 0 ], [ 0.001, -0.074 ], [ 0, -13.484 ], [ -1.778, 0 ], [ -3.594, -18.742 ], [ -20.03, 0 ], [ -2.421, -0.804 ], [ -13.485, 0 ], [ 0, 0.642 ], [ -1.89, -1.199 ], [ -6.742, 0 ], [ 0, 6.743 ], [ 0, 0 ], [ 6.742, 0 ], [ 0, -6.742 ] ], "v": [ [ 75.134, 16.175 ], [ 72.85, 16.396 ], [ 72.856, 16.175 ], [ 48.44, -8.241 ], [ 43.262, -7.685 ], [ 3.406, -40.591 ], [ -36.571, -6.995 ], [ -44.269, -8.241 ], [ -68.685, 16.175 ], [ -68.604, 18.079 ], [ -75.133, 16.175 ], [ -87.341, 28.383 ], [ -75.133, 40.592 ], [ 75.134, 40.592 ], [ 87.342, 28.383 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.815686334348, 0.823529471603, 0.827451040231, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 453.672, 304.756 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 4", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false } ], "ip": 0, "op": 151, "st": 0, "bm": 0 }, { "ddd": 0, "ind": 2, "ty": 4, "nm": "Merged Shape Layer", "sr": 1, "ks": { "o": { "a": 0, "k": 100, "ix": 11 }, "r": { "a": 1, "k": [ { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.547 ], "y": [ 0 ] }, "t": 0, "s": [ 0 ] }, { "i": { "x": [ 0.845 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 77, "s": [ 35 ] }, { "t": 150, "s": [ 0 ] } ], "ix": 10 }, "p": { "a": 1, "k": [ { "i": { "x": 0.667, "y": 1 }, "o": { "x": 0.333, "y": 0 }, "t": 0, "s": [ 390.319, 298.2, 0 ], "to": [ 0, -2.583, 0 ], "ti": [ 0, 0, 0 ] }, { "i": { "x": 0.667, "y": 1 }, "o": { "x": 0.333, "y": 0 }, "t": 44, "s": [ 390.319, 282.7, 0 ], "to": [ 0, 0, 0 ], "ti": [ 0, 0, 0 ] }, { "i": { "x": 0.667, "y": 1 }, "o": { "x": 0.333, "y": 0 }, "t": 110, "s": [ 390.319, 319.25, 0 ], "to": [ 0, 0, 0 ], "ti": [ 0, 0, 0 ] }, { "t": 150, "s": [ 390.319, 298.2, 0 ] } ], "ix": 2 }, "a": { "a": 0, "k": [ 664.319, 256.2, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100, 100 ], "ix": 6 } }, "ao": 0, "shapes": [ { "ty": "gr", "it": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "o": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "v": [ [ 18.967, -3.189 ], [ -18.967, 19.935 ], [ -0.949, -19.935 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.223528981209, 0.192156970501, 0.674510002136, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 236.879, 292.737 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 1", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 633.939, 275.369 ], "ix": 2 }, "a": { "a": 0, "k": [ 236.879, 292.737 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "planete Outlines - Group 1", "np": 1, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "gr", "it": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "o": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "v": [ [ -98.335, 64.79 ], [ -105.619, 4.984 ], [ 105.619, -64.79 ], [ -80.316, 24.919 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.278430998325, 0.294117987156, 0.847059011459, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 316.247, 247.882 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 2", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 673.623, 252.941 ], "ix": 2 }, "a": { "a": 0, "k": [ 316.247, 247.882 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "planete Outlines - Group 2", "np": 1, "cix": 2, "bm": 0, "ix": 2, "mn": "ADBE Vector Group", "hd": false }, { "ty": "gr", "it": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "o": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "v": [ [ -133.812, -42.171 ], [ 133.812, -75.141 ], [ 5.765, 75.141 ], [ -61.708, 18.402 ], [ 124.227, -71.307 ], [ -87.011, -1.534 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.365000009537, 0.407999992371, 0.976000010967, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 297.638, 254.4 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 3", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 664.319, 256.2 ], "ix": 2 }, "a": { "a": 0, "k": [ 297.638, 254.4 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "planete Outlines - Group 3", "np": 1, "cix": 2, "bm": 0, "ix": 3, "mn": "ADBE Vector Group", "hd": false } ], "ip": 0, "op": 151, "st": 0, "bm": 0 }, { "ddd": 0, "ind": 3, "ty": 4, "nm": "planete Outlines - Group 5", "sr": 1, "ks": { "o": { "a": 1, "k": [ { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 0, "s": [ 0 ] }, { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 45, "s": [ 100 ] }, { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 102, "s": [ 100 ] }, { "t": 150, "s": [ 0 ] } ], "ix": 11 }, "r": { "a": 0, "k": 0, "ix": 10 }, "p": { "a": 1, "k": [ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 0, "s": [ 327.38, 267.583, 0 ], "to": [ 25.833, 0, 0 ], "ti": [ -25.833, 0, 0 ] }, { "t": 150, "s": [ 482.38, 267.583, 0 ] } ], "ix": 2 }, "a": { "a": 0, "k": [ 171.76, 193.166, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50, 100 ], "ix": 6 } }, "ao": 0, "shapes": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 13.485, 0 ], [ 4.38, -4.171 ], [ 21.913, 0 ], [ 3.575, -18.765 ], [ 1.851, 0 ], [ 0, -13.484 ], [ -0.011, -0.291 ], [ 1.599, 0 ], [ 0, -6.743 ], [ -6.742, 0 ], [ 0, 0 ], [ 0, 13.485 ] ], "o": [ [ -6.526, 0 ], [ -0.793, -21.719 ], [ -19.806, 0 ], [ -1.734, -0.391 ], [ -13.485, 0 ], [ 0, 0.293 ], [ -1.4, -0.559 ], [ -6.742, 0 ], [ 0, 6.742 ], [ 0, 0 ], [ 13.485, 0 ], [ 0, -13.484 ] ], "v": [ [ 59.669, -8.242 ], [ 42.84, -1.506 ], [ 2.287, -40.592 ], [ -37.576, -7.638 ], [ -42.962, -8.242 ], [ -67.378, 16.174 ], [ -67.356, 17.049 ], [ -71.878, 16.174 ], [ -84.086, 28.383 ], [ -71.878, 40.591 ], [ 59.669, 40.591 ], [ 84.086, 16.174 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.816000007181, 0.823999980852, 0.827000038297, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 171.76, 193.166 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 5", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false } ], "ip": 0, "op": 151, "st": 0, "bm": 0 } ] } ], "layers": [ { "ddd": 0, "ind": 1, "ty": 0, "nm": "Pre-comp 1", "refId": "comp_0", "sr": 1, "ks": { "o": { "a": 0, "k": 100, "ix": 11 }, "r": { "a": 0, "k": 0, "ix": 10 }, "p": { "a": 0, "k": [ 406, 306, 0 ], "ix": 2 }, "a": { "a": 0, "k": [ 400, 300, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 179, 179, 100 ], "ix": 6 } }, "ao": 0, "w": 800, "h": 600, "ip": 0, "op": 147, "st": 0, "bm": 0 } ], "markers": [] } ================================================ FILE: simple_live_app/assets/statement.txt ================================================ 在使用本软件之前,请您仔细阅读以下内容,并确保您充分理解并同意以下条款: 1、本软件为开源软件,您可以免费获取并使用该软件。 2、本软件完全基于您个人意愿使用,您应该对自己的使用行为和所有结果承担全部责任。 3、本软件仅供学习交流、科研等非商业性质的用途,严禁将本软件用于商业目的。如有任何商业行为,均与本软件无关。 4、本软件并不保证与所有操作系统或硬件设备兼容。本软件作者或贡献者不对因使用本软件而产生的任何技术或安全问题承担责任。 5、本软件作者或贡献者不承担因使用本软件而造成的任何直接、间接、特殊或后果性的损失或损害的责任,包括但不限于财产损失、商业利润损失、信息或数据丢失或损坏等。 6、本软件使用者应遵守国家相关法律法规和使用规范,不得利用本软件从事任何违法违规行为。如因使用本软件而导致的违法行为,使用者应承担相应的法律责任。 7、本软件不会收集、存储、使用任何用户的个人信息,包括但不限于姓名、地址、电子邮件地址、电话号码等。在使用本软件过程中,不会进行任何形式的个人信息采集。如用户提供任何个人信息,将被视为用户已自愿提供,并且用户将自行承担由此产生的所有法律责任。 8、本软件作者或贡献者保留随时修改、增加、删除本免责声明中的内容而不另行通知的权利。 9、如果本软件存在侵犯您的合法权益的情况,请及时与作者联系,作者将会及时删除有关内容。 如您不同意本免责声明中的任何内容,请勿使用本软件。使用本软件即代表您已完全理解并同意上述内容。 ================================================ FILE: simple_live_app/distribute_options.yaml ================================================ output: build/dist/ ================================================ FILE: simple_live_app/ios/.gitignore ================================================ **/dgph *.mode1v3 *.mode2v3 *.moved-aside *.pbxuser *.perspectivev3 **/*sync/ .sconsign.dblite .tags* **/.vagrant/ **/DerivedData/ Icon? **/Pods/ **/.symlinks/ profile xcuserdata **/.generated/ Flutter/App.framework Flutter/Flutter.framework Flutter/Flutter.podspec Flutter/Generated.xcconfig Flutter/ephemeral/ Flutter/app.flx Flutter/app.zip Flutter/flutter_assets/ Flutter/flutter_export_environment.sh ServiceDefinitions.json Runner/GeneratedPluginRegistrant.* # Exceptions to above rules. !default.mode1v3 !default.mode2v3 !default.pbxuser !default.perspectivev3 ================================================ FILE: simple_live_app/ios/Flutter/AppFrameworkInfo.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable App CFBundleIdentifier io.flutter.flutter.app CFBundleInfoDictionaryVersion 6.0 CFBundleName App CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 MinimumOSVersion 13.0 ================================================ FILE: simple_live_app/ios/Flutter/Debug.xcconfig ================================================ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" ================================================ FILE: simple_live_app/ios/Flutter/Release.xcconfig ================================================ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" ================================================ FILE: simple_live_app/ios/Podfile ================================================ # Uncomment this line to define a global platform for your project platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } def flutter_root generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) unless File.exist?(generated_xcode_build_settings_path) raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" end File.foreach(generated_xcode_build_settings_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/) return matches[1].strip if matches end raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) flutter_ios_podfile_setup target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) target.build_configurations.each do |config| config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [ '$(inherited)', ## dart: PermissionGroup.calendar # 'PERMISSION_EVENTS=1', ## dart: PermissionGroup.reminders # 'PERMISSION_REMINDERS=1', ## dart: PermissionGroup.contacts # 'PERMISSION_CONTACTS=1', ## dart: PermissionGroup.camera #'PERMISSION_CAMERA=1', ## dart: PermissionGroup.microphone # 'PERMISSION_MICROPHONE=1', ## dart: PermissionGroup.speech # 'PERMISSION_SPEECH_RECOGNIZER=1', ## dart: PermissionGroup.photos 'PERMISSION_PHOTOS=1', ## dart: [PermissionGroup.location, PermissionGroup.locationAlways, PermissionGroup.locationWhenInUse] #'PERMISSION_LOCATION=1', ## dart: PermissionGroup.notification #'PERMISSION_NOTIFICATIONS=1', ## dart: PermissionGroup.mediaLibrary # 'PERMISSION_MEDIA_LIBRARY=1', ## dart: PermissionGroup.sensors # 'PERMISSION_SENSORS=1', ## dart: PermissionGroup.bluetooth # 'PERMISSION_BLUETOOTH=1', ## dart: PermissionGroup.appTrackingTransparency # 'PERMISSION_APP_TRACKING_TRANSPARENCY=1', ## dart: PermissionGroup.criticalAlerts # 'PERMISSION_CRITICAL_ALERTS=1' ] end end end ================================================ FILE: simple_live_app/ios/Runner/AppDelegate.swift ================================================ import UIKit import Flutter @main @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { return super.application(application, didFinishLaunchingWithOptions: launchOptions) } func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) { GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry) } } ================================================ FILE: simple_live_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images": [ { "size": "20x20", "idiom": "iphone", "filename": "icon-20@2x.png", "scale": "2x" }, { "size": "20x20", "idiom": "iphone", "filename": "icon-20@3x.png", "scale": "3x" }, { "size": "29x29", "idiom": "iphone", "filename": "icon-29.png", "scale": "1x" }, { "size": "29x29", "idiom": "iphone", "filename": "icon-29@2x.png", "scale": "2x" }, { "size": "29x29", "idiom": "iphone", "filename": "icon-29@3x.png", "scale": "3x" }, { "size": "40x40", "idiom": "iphone", "filename": "icon-40@2x.png", "scale": "2x" }, { "size": "40x40", "idiom": "iphone", "filename": "icon-40@3x.png", "scale": "3x" }, { "size": "60x60", "idiom": "iphone", "filename": "icon-60@2x.png", "scale": "2x" }, { "size": "60x60", "idiom": "iphone", "filename": "icon-60@3x.png", "scale": "3x" }, { "size": "20x20", "idiom": "ipad", "filename": "icon-20-ipad.png", "scale": "1x" }, { "size": "20x20", "idiom": "ipad", "filename": "icon-20@2x-ipad.png", "scale": "2x" }, { "size": "29x29", "idiom": "ipad", "filename": "icon-29-ipad.png", "scale": "1x" }, { "size": "29x29", "idiom": "ipad", "filename": "icon-29@2x-ipad.png", "scale": "2x" }, { "size": "40x40", "idiom": "ipad", "filename": "icon-40.png", "scale": "1x" }, { "size": "40x40", "idiom": "ipad", "filename": "icon-40@2x.png", "scale": "2x" }, { "size": "76x76", "idiom": "ipad", "filename": "icon-76.png", "scale": "1x" }, { "size": "76x76", "idiom": "ipad", "filename": "icon-76@2x.png", "scale": "2x" }, { "size": "83.5x83.5", "idiom": "ipad", "filename": "icon-83.5@2x.png", "scale": "2x" }, { "size": "1024x1024", "idiom": "ios-marketing", "filename": "icon-1024.png", "scale": "1x" } ], "info": { "version": 1, "author": "icon.wuruihong.com" } } ================================================ FILE: simple_live_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json ================================================ { "images" : [ { "idiom" : "universal", "filename" : "LaunchImage.png", "scale" : "1x" }, { "idiom" : "universal", "filename" : "LaunchImage@2x.png", "scale" : "2x" }, { "idiom" : "universal", "filename" : "LaunchImage@3x.png", "scale" : "3x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: simple_live_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md ================================================ # Launch Screen Assets You can customize the launch screen with your own desired assets by replacing the image files in this directory. You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. ================================================ FILE: simple_live_app/ios/Runner/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: simple_live_app/ios/Runner/Base.lproj/Main.storyboard ================================================ ================================================ FILE: simple_live_app/ios/Runner/Info.plist ================================================ CADisableMinimumFrameDurationOnPhone CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName Simple Live CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName simple_live_app CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleSignature ???? CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSRequiresIPhoneOS NSAppTransportSecurity NSAllowsArbitraryLoads UIApplicationSupportsIndirectInputEvents UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance UIBackgroundModes audio NSPhotoLibraryUsageDescription 保存图片至相册 UISupportsDocumentBrowser io.flutter.embedded_views_preview NSCameraUsageDescription 用于扫描二维码 UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneClassNameUIWindowScene UISceneDelegateClassNameFlutterSceneDelegate UISceneConfigurationNameflutter UISceneStoryboardFileMain ================================================ FILE: simple_live_app/ios/Runner/Runner-Bridging-Header.h ================================================ #import "GeneratedPluginRegistrant.h" ================================================ FILE: simple_live_app/ios/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 73C9599770D417F3E7B681E2 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 60E92DDDD814CB6531C03BCD /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 9705A1C41CF9048500538489 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 0874FB99E210639E7D21C1F0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 2778CC04696D7C0E532931A0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 60E92DDDD814CB6531C03BCD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 6C36D91D13E89663DBB13E51 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 73C9599770D417F3E7B681E2 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 65B8FB167D986F3BCF168FB6 /* Frameworks */ = { isa = PBXGroup; children = ( 60E92DDDD814CB6531C03BCD /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */, ); name = Flutter; sourceTree = ""; }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, FD158AC2F4211953A42B4A25 /* Pods */, 65B8FB167D986F3BCF168FB6 /* Frameworks */, ); sourceTree = ""; }; 97C146EF1CF9000F007C117D /* Products */ = { isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, ); name = Products; sourceTree = ""; }; 97C146F01CF9000F007C117D /* Runner */ = { isa = PBXGroup; children = ( 97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C147021CF9000F007C117D /* Info.plist */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, ); path = Runner; sourceTree = ""; }; FD158AC2F4211953A42B4A25 /* Pods */ = { isa = PBXGroup; children = ( 2778CC04696D7C0E532931A0 /* Pods-Runner.debug.xcconfig */, 6C36D91D13E89663DBB13E51 /* Pods-Runner.release.xcconfig */, 0874FB99E210639E7D21C1F0 /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 97C146ED1CF9000F007C117D /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( EEC3C9B6719E92514BD4D205 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 6D32CBFCD866586D78A69BE1 /* [CP] Embed Pods Frameworks */, 92FA5F4E31AA12D8C9AA408A /* [CP] Copy Pods Resources */, ); buildRules = ( ); dependencies = ( ); name = Runner; productName = Runner; productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { CreatedOnToolsVersion = 7.3.1; LastSwiftMigration = 1100; }; }; }; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 97C146E51CF9000F007C117D; productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 97C146EC1CF9000F007C117D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; 6D32CBFCD866586D78A69BE1 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 92FA5F4E31AA12D8C9AA408A /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; EEC3C9B6719E92514BD4D205 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 97C146EA1CF9000F007C117D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 97C146FA1CF9000F007C117D /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 97C146FB1CF9000F007C117D /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 97C147001CF9000F007C117D /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Profile; }; 249021D4217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 9R87RMF9C9; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.xycz.simple-live"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Profile; }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 97C147061CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 9R87RMF9C9; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.xycz.simple-live"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 97C147071CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = 9R87RMF9C9; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); PRODUCT_BUNDLE_IDENTIFIER = "com.xycz.simple-live"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, 97C147041CF9000F007C117D /* Release */, 249021D3217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, 97C147071CF9000F007C117D /* Release */, 249021D4217E4FDB00AE95B9 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 97C146E61CF9000F007C117D /* Project object */; } ================================================ FILE: simple_live_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: simple_live_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: simple_live_app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ PreviewsEnabled ================================================ FILE: simple_live_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: simple_live_app/ios/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: simple_live_app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: simple_live_app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ PreviewsEnabled ================================================ FILE: simple_live_app/lib/app/app_style.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; class AppColors { static ColorScheme lightColorScheme = ColorScheme.fromSeed( // primarySwatch: Colors.blue, seedColor: const Color(0xff3498db), brightness: Brightness.light, ); static ColorScheme darkColorScheme = ColorScheme.fromSeed( seedColor: const Color(0xff3498db), brightness: Brightness.dark, ); static const Color black333 = Color(0xFF333333); } class AppStyle { static ThemeData lightTheme = ThemeData( colorScheme: AppColors.lightColorScheme, useMaterial3: true, fontFamily: Platform.isWindows ? "Microsoft YaHei" : null, visualDensity: VisualDensity.standard, appBarTheme: AppBarTheme( //elevation: 0, centerTitle: true, titleTextStyle: const TextStyle( fontSize: 16, color: AppColors.black333, ), foregroundColor: AppColors.black333, systemOverlayStyle: SystemUiOverlayStyle.dark.copyWith( systemNavigationBarColor: Colors.transparent, ), ), // radioTheme: RadioThemeData( // fillColor: MaterialStateProperty.all(AppColors.lightColorScheme.primary), // ), // checkboxTheme: CheckboxThemeData( // fillColor: MaterialStateProperty.all(AppColors.lightColorScheme.primary), // ), // tabBarTheme: TabBarTheme( // labelColor: AppColors.lightColorScheme.primary, // unselectedLabelColor: Colors.white70, // indicatorSize: TabBarIndicatorSize.tab, // indicator: RectangularIndicator( // color: Colors.white.withOpacity(.8), // topLeftRadius: 24, // bottomLeftRadius: 24, // topRightRadius: 24, // bottomRightRadius: 24, // verticalPadding: 8, // horizontalPadding: 0, // ), // ), ); static ThemeData darkTheme = ThemeData.dark().copyWith( colorScheme: AppColors.darkColorScheme, visualDensity: VisualDensity.standard, textTheme: ThemeData.dark().textTheme.apply( fontFamily: Platform.isWindows ? "Microsoft YaHei" : null, ), primaryTextTheme: ThemeData().textTheme.apply( fontFamily: Platform.isWindows ? "Microsoft YaHei" : null, ), appBarTheme: AppBarTheme( //elevation: 0, centerTitle: true, titleTextStyle: const TextStyle( fontSize: 16, color: Colors.white, ), foregroundColor: Colors.white, systemOverlayStyle: SystemUiOverlayStyle.light.copyWith( systemNavigationBarColor: Colors.transparent, ), ), // radioTheme: RadioThemeData( // fillColor: MaterialStateProperty.all(AppColors.darkColorScheme.primary), // ), // checkboxTheme: CheckboxThemeData( // fillColor: MaterialStateProperty.all(AppColors.darkColorScheme.primary), // ), // tabBarTheme: TabBarTheme( // labelColor: AppColors.darkColorScheme.primary, // unselectedLabelColor: Colors.white70, // indicator: RectangularIndicator( // color: Colors.white.withAlpha(50), // topLeftRadius: 24, // bottomLeftRadius: 24, // topRightRadius: 24, // bottomRightRadius: 24, // verticalPadding: 8, // horizontalPadding: 0, // ), // ), ); static const vGap4 = SizedBox( height: 4, ); static const vGap8 = SizedBox( height: 8, ); static const vGap12 = SizedBox( height: 12, ); static const vGap24 = SizedBox( height: 24, ); static const vGap32 = SizedBox( height: 32, ); static const vGap48 = SizedBox( height: 48, ); static const hGap4 = SizedBox( width: 4, ); static const hGap8 = SizedBox( width: 8, ); static const hGap12 = SizedBox( width: 12, ); static const hGap16 = SizedBox( width: 16, ); static const hGap24 = SizedBox( width: 24, ); static const hGap32 = SizedBox( width: 32, ); static const hGap48 = SizedBox( width: 48, ); static const edgeInsetsH4 = EdgeInsets.symmetric(horizontal: 4); static const edgeInsetsH8 = EdgeInsets.symmetric(horizontal: 8); static const edgeInsetsH12 = EdgeInsets.symmetric(horizontal: 12); static const edgeInsetsH16 = EdgeInsets.symmetric(horizontal: 16); static const edgeInsetsH20 = EdgeInsets.symmetric(horizontal: 20); static const edgeInsetsH24 = EdgeInsets.symmetric(horizontal: 24); static const edgeInsetsV4 = EdgeInsets.symmetric(vertical: 4); static const edgeInsetsV8 = EdgeInsets.symmetric(vertical: 8); static const edgeInsetsV12 = EdgeInsets.symmetric(vertical: 12); static const edgeInsetsV24 = EdgeInsets.symmetric(vertical: 24); static const edgeInsetsA4 = EdgeInsets.all(4); static const edgeInsetsA8 = EdgeInsets.all(8); static const edgeInsetsA12 = EdgeInsets.all(12); static const edgeInsetsA16 = EdgeInsets.all(16); static const edgeInsetsA20 = EdgeInsets.all(20); static const edgeInsetsA24 = EdgeInsets.all(24); static const edgeInsetsR4 = EdgeInsets.only(right: 4); static const edgeInsetsR8 = EdgeInsets.only(right: 8); static const edgeInsetsR12 = EdgeInsets.only(right: 12); static const edgeInsetsR16 = EdgeInsets.only(right: 16); static const edgeInsetsR20 = EdgeInsets.only(right: 20); static const edgeInsetsR24 = EdgeInsets.only(right: 24); static const edgeInsetsL4 = EdgeInsets.only(left: 4); static const edgeInsetsL8 = EdgeInsets.only(left: 8); static const edgeInsetsL12 = EdgeInsets.only(left: 12); static const edgeInsetsL16 = EdgeInsets.only(left: 16); static const edgeInsetsL20 = EdgeInsets.only(left: 20); static const edgeInsetsL24 = EdgeInsets.only(left: 24); static const edgeInsetsT4 = EdgeInsets.only(top: 4); static const edgeInsetsT8 = EdgeInsets.only(top: 8); static const edgeInsetsT12 = EdgeInsets.only(top: 12); static const edgeInsetsT24 = EdgeInsets.only(top: 24); static const edgeInsetsB4 = EdgeInsets.only(bottom: 4); static const edgeInsetsB8 = EdgeInsets.only(bottom: 8); static const edgeInsetsB12 = EdgeInsets.only(bottom: 12); static const edgeInsetsB24 = EdgeInsets.only(bottom: 24); static BorderRadius radius4 = BorderRadius.circular(4); static BorderRadius radius8 = BorderRadius.circular(8); static BorderRadius radius12 = BorderRadius.circular(12); static BorderRadius radius24 = BorderRadius.circular(24); static BorderRadius radius32 = BorderRadius.circular(32); static BorderRadius radius48 = BorderRadius.circular(48); /// 顶部状态栏的高度 static double get statusBarHeight => MediaQuery.of(Get.context!).padding.top; /// 底部导航条的高度 static double get bottomBarHeight => MediaQuery.of(Get.context!).padding.bottom; static Divider get divider => Divider( height: 1, thickness: 1, indent: 16, endIndent: 16, color: Colors.grey.withAlpha(25), ); } ================================================ FILE: simple_live_app/lib/app/constant.dart ================================================ import 'package:flutter/material.dart'; import 'package:remixicon/remixicon.dart'; class Constant { static const String kUpdateFollow = "UpdateFollow"; static const String kUpdateHistory = "UpdateHistory"; static final Map allHomePages = { "recommend": HomePageItem( iconData: Remix.home_smile_line, title: "首页", index: 0, ), "follow": HomePageItem( iconData: Remix.heart_line, title: "关注", index: 1, ), "category": HomePageItem( iconData: Remix.apps_line, title: "分类", index: 2, ), "user": HomePageItem( iconData: Remix.user_smile_line, title: "我的", index: 3, ), }; static const String kBiliBili = "bilibili"; static const String kDouyu = "douyu"; static const String kHuya = "huya"; static const String kDouyin = "douyin"; } class HomePageItem { final IconData iconData; final String title; final int index; HomePageItem({ required this.iconData, required this.title, required this.index, }); } ================================================ FILE: simple_live_app/lib/app/controller/app_settings_controller.dart ================================================ import 'dart:io'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/services/local_storage_service.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; class AppSettingsController extends GetxController { static AppSettingsController get instance => Get.find(); /// 缩放模式 var scaleMode = 0.obs; var themeMode = 0.obs; var firstRun = false; @override void onInit() { themeMode.value = LocalStorageService.instance .getValue(LocalStorageService.kThemeMode, 0); firstRun = LocalStorageService.instance .getValue(LocalStorageService.kFirstRun, true); danmuSize.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuSize, 16.0); danmuOpacity.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuOpacity, 1.0); danmuArea.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuArea, 0.8); danmuSpeed.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuSpeed, 10.0); danmuEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuEnable, true); danmuStrokeWidth.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuStrokeWidth, 2.0); danmuTopMargin.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuTopMargin, 0.0); danmuBottomMargin.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuBottomMargin, 0.0); danmuFontWeight.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuFontWeight, 4); hardwareDecode.value = LocalStorageService.instance .getValue(LocalStorageService.kHardwareDecode, true); chatTextSize.value = LocalStorageService.instance .getValue(LocalStorageService.kChatTextSize, 14.0); chatTextGap.value = LocalStorageService.instance .getValue(LocalStorageService.kChatTextGap, 4.0); chatBubbleStyle.value = LocalStorageService.instance.getValue( LocalStorageService.kChatBubbleStyle, false, ); qualityLevel.value = LocalStorageService.instance .getValue(LocalStorageService.kQualityLevel, 1); qualityLevelCellular.value = LocalStorageService.instance .getValue(LocalStorageService.kQualityLevelCellular, 1); autoExitEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoExitEnable, false); autoExitDuration.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoExitDuration, 60); roomAutoExitDuration.value = LocalStorageService.instance .getValue(LocalStorageService.kRoomAutoExitDuration, 60); playerCompatMode.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerCompatMode, false); playerAutoPause.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerAutoPause, false); playerForceHttps.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerForceHttps, false); autoFullScreen.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoFullScreen, false); // ignore: invalid_use_of_protected_member shieldList.value = LocalStorageService.instance.shieldBox.values.toSet(); scaleMode.value = LocalStorageService.instance.getValue( LocalStorageService.kPlayerScaleMode, 0, ); playerVolume.value = LocalStorageService.instance.getValue( LocalStorageService.kPlayerVolume, 100.0, ); pipHideDanmu.value = LocalStorageService.instance .getValue(LocalStorageService.kPIPHideDanmu, true); styleColor.value = LocalStorageService.instance .getValue(LocalStorageService.kStyleColor, 0xff3498db); isDynamic.value = LocalStorageService.instance .getValue(LocalStorageService.kIsDynamic, false); bilibiliLoginTip.value = LocalStorageService.instance .getValue(LocalStorageService.kBilibiliLoginTip, true); playerBufferSize.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerBufferSize, 32); logEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kLogEnable, false); if (logEnable.value) { Log.initWriter(); } customPlayerOutput.value = LocalStorageService.instance .getValue(LocalStorageService.kCustomPlayerOutput, false); videoOutputDriver.value = LocalStorageService.instance.getValue( LocalStorageService.kVideoOutputDriver, Platform.isAndroid ? "gpu" : "libmpv", ); audioOutputDriver.value = LocalStorageService.instance.getValue( LocalStorageService.kAudioOutputDriver, Platform.isAndroid ? "audiotrack" : Platform.isLinux ? "pulse" : Platform.isWindows ? "wasapi" : Platform.isIOS ? "audiounit" : Platform.isMacOS ? "coreaudio" : "sdl", ); videoHardwareDecoder.value = LocalStorageService.instance.getValue( LocalStorageService.kVideoHardwareDecoder, Platform.isAndroid ? "auto-safe" : "auto", ); autoUpdateFollowEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoUpdateFollowEnable, true); autoUpdateFollowDuration.value = LocalStorageService.instance .getValue(LocalStorageService.kUpdateFollowDuration, 10); updateFollowThreadCount.value = LocalStorageService.instance .getValue(LocalStorageService.kUpdateFollowThreadCount, 0); // 默认 0 = 自动 initSiteSort(); initHomeSort(); super.onInit(); } void initSiteSort() { var sort = LocalStorageService.instance .getValue( LocalStorageService.kSiteSort, Sites.allSites.keys.join(","), ) .split(","); //如果数量与allSites的数量不一致,将缺失的添加上 if (sort.length != Sites.allSites.length) { var keys = Sites.allSites.keys.toList(); for (var i = 0; i < keys.length; i++) { if (!sort.contains(keys[i])) { sort.add(keys[i]); } } } siteSort.value = sort; } void initHomeSort() { var sort = LocalStorageService.instance .getValue( LocalStorageService.kHomeSort, Constant.allHomePages.keys.join(","), ) .split(","); //如果数量与allSites的数量不一致,将缺失的添加上 if (sort.length != Constant.allHomePages.length) { var keys = Constant.allHomePages.keys.toList(); for (var i = 0; i < keys.length; i++) { if (!sort.contains(keys[i])) { sort.add(keys[i]); } } } homeSort.value = sort; } void setNoFirstRun() { LocalStorageService.instance.setValue(LocalStorageService.kFirstRun, false); } void changeTheme() { Get.dialog( RadioGroup( groupValue: themeMode.value, onChanged: (e) { Get.back(); setTheme(e ?? 0); }, child: const SimpleDialog( title: Text("设置主题"), children: [ RadioListTile( title: Text("跟随系统"), value: 0, ), RadioListTile( title: Text("浅色模式"), value: 1, ), RadioListTile( title: Text("深色模式"), value: 2, ), ], ), ), ); } void setTheme(int i) { themeMode.value = i; var mode = ThemeMode.values[i]; LocalStorageService.instance.setValue(LocalStorageService.kThemeMode, i); Get.changeThemeMode(mode); } var hardwareDecode = true.obs; void setHardwareDecode(bool e) { hardwareDecode.value = e; LocalStorageService.instance .setValue(LocalStorageService.kHardwareDecode, e); } var chatTextSize = 14.0.obs; void setChatTextSize(double e) { chatTextSize.value = e; LocalStorageService.instance.setValue(LocalStorageService.kChatTextSize, e); } var chatTextGap = 4.0.obs; void setChatTextGap(double e) { chatTextGap.value = e; LocalStorageService.instance.setValue(LocalStorageService.kChatTextGap, e); } var chatBubbleStyle = false.obs; void setChatBubbleStyle(bool e) { chatBubbleStyle.value = e; LocalStorageService.instance .setValue(LocalStorageService.kChatBubbleStyle, e); } var danmuSize = 16.0.obs; void setDanmuSize(double e) { danmuSize.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuSize, e); } var danmuSpeed = 10.0.obs; void setDanmuSpeed(double e) { danmuSpeed.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuSpeed, e); } var danmuArea = 0.8.obs; void setDanmuArea(double e) { danmuArea.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuArea, e); } var danmuOpacity = 1.0.obs; void setDanmuOpacity(double e) { danmuOpacity.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuOpacity, e); } var danmuEnable = true.obs; void setDanmuEnable(bool e) { danmuEnable.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuEnable, e); } var danmuStrokeWidth = 2.0.obs; void setDanmuStrokeWidth(double e) { danmuStrokeWidth.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuStrokeWidth, e); } var danmuFontWeight = 4.obs; void setDanmuFontWeight(int e) { danmuFontWeight.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuFontWeight, e); } var qualityLevel = 1.obs; void setQualityLevel(int level) { qualityLevel.value = level; LocalStorageService.instance .setValue(LocalStorageService.kQualityLevel, level); } var qualityLevelCellular = 1.obs; void setQualityLevelCellular(int level) { qualityLevelCellular.value = level; LocalStorageService.instance .setValue(LocalStorageService.kQualityLevelCellular, level); } var autoExitEnable = false.obs; void setAutoExitEnable(bool e) { autoExitEnable.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoExitEnable, e); } var autoExitDuration = 60.obs; void setAutoExitDuration(int e) { autoExitDuration.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoExitDuration, e); } var roomAutoExitDuration = 60.obs; void setRoomAutoExitDuration(int e) { roomAutoExitDuration.value = e; LocalStorageService.instance .setValue(LocalStorageService.kRoomAutoExitDuration, e); } var playerCompatMode = false.obs; void setPlayerCompatMode(bool e) { playerCompatMode.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerCompatMode, e); } var playerBufferSize = 32.obs; void setPlayerBufferSize(int e) { playerBufferSize.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerBufferSize, e); } var playerAutoPause = false.obs; void setPlayerAutoPause(bool e) { playerAutoPause.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerAutoPause, e); } var autoFullScreen = false.obs; void setAutoFullScreen(bool e) { autoFullScreen.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoFullScreen, e); } var playershowSuperChat = true.obs; void setPlayerShowSuperChat(bool e) { playershowSuperChat.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerShowSuperChat, e); } RxSet shieldList = {}.obs; void addShieldList(String e) { shieldList.add(e); LocalStorageService.instance.shieldBox.put(e, e); } void removeShieldList(String e) { shieldList.remove(e); LocalStorageService.instance.shieldBox.delete(e); } Future clearShieldList() async { shieldList.clear(); await LocalStorageService.instance.shieldBox.clear(); } void setScaleMode(int value) { scaleMode.value = value; LocalStorageService.instance.setValue( LocalStorageService.kPlayerScaleMode, value, ); } RxList siteSort = RxList(); void setSiteSort(List e) { siteSort.value = e; LocalStorageService.instance.setValue( LocalStorageService.kSiteSort, siteSort.join(","), ); } RxList homeSort = RxList(); void setHomeSort(List e) { homeSort.value = e; LocalStorageService.instance.setValue( LocalStorageService.kHomeSort, homeSort.join(","), ); } Rx playerVolume = 100.0.obs; void setPlayerVolume(double value) { playerVolume.value = value; LocalStorageService.instance.setValue( LocalStorageService.kPlayerVolume, value, ); } var pipHideDanmu = true.obs; void setPIPHideDanmu(bool e) { pipHideDanmu.value = e; LocalStorageService.instance.setValue(LocalStorageService.kPIPHideDanmu, e); } var styleColor = 0xff3498db.obs; void setStyleColor(int e) { styleColor.value = e; LocalStorageService.instance.setValue(LocalStorageService.kStyleColor, e); } var isDynamic = false.obs; void setIsDynamic(bool e) { isDynamic.value = e; LocalStorageService.instance.setValue(LocalStorageService.kIsDynamic, e); } var danmuTopMargin = 0.0.obs; void setDanmuTopMargin(double e) { danmuTopMargin.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuTopMargin, e); } var danmuBottomMargin = 0.0.obs; void setDanmuBottomMargin(double e) { danmuBottomMargin.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuBottomMargin, e); } var bilibiliLoginTip = true.obs; void setBiliBiliLoginTip(bool e) { bilibiliLoginTip.value = e; LocalStorageService.instance .setValue(LocalStorageService.kBilibiliLoginTip, e); } var logEnable = false.obs; void setLogEnable(bool e) { logEnable.value = e; LocalStorageService.instance.setValue(LocalStorageService.kLogEnable, e); } var customPlayerOutput = false.obs; void setCustomPlayerOutput(bool e) { customPlayerOutput.value = e; LocalStorageService.instance .setValue(LocalStorageService.kCustomPlayerOutput, e); } var videoOutputDriver = "".obs; void setVideoOutputDriver(String e) { videoOutputDriver.value = e; LocalStorageService.instance .setValue(LocalStorageService.kVideoOutputDriver, e); } var audioOutputDriver = "".obs; void setAudioOutputDriver(String e) { audioOutputDriver.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAudioOutputDriver, e); } var videoHardwareDecoder = "".obs; void setVideoHardwareDecoder(String e) { videoHardwareDecoder.value = e; LocalStorageService.instance .setValue(LocalStorageService.kVideoHardwareDecoder, e); } var autoUpdateFollowEnable = false.obs; void setAutoUpdateFollowEnable(bool e) { autoUpdateFollowEnable.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoUpdateFollowEnable, e); } var autoUpdateFollowDuration = 10.obs; void setAutoUpdateFollowDuration(int e) { autoUpdateFollowDuration.value = e; LocalStorageService.instance .setValue(LocalStorageService.kUpdateFollowDuration, e); } var updateFollowThreadCount = 4.obs; void setUpdateFollowThreadCount(int e) { updateFollowThreadCount.value = e; LocalStorageService.instance .setValue(LocalStorageService.kUpdateFollowThreadCount, e); } var playerForceHttps = false.obs; void setPlayerForceHttps(bool e) { playerForceHttps.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerForceHttps, e); } } ================================================ FILE: simple_live_app/lib/app/controller/base_controller.dart ================================================ import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; class BaseController extends GetxController { /// 加载中,更新页面 var pageLoadding = false.obs; /// 加载中,不会更新页面 var loadding = false; /// 空白页面 var pageEmpty = false.obs; /// 页面错误 var pageError = false.obs; /// 未登录 var notLogin = false.obs; /// 错误信息 var errorMsg = "".obs; /// 显示错误 /// * [msg] 错误信息 /// * [showPageError] 显示页面错误 /// * 只在第一页加载错误时showPageError=true,后续页加载错误时使用Toast弹出通知 void handleError(Object exception, {bool showPageError = false}) { Log.e(exception.toString(), StackTrace.current); var msg = exceptionToString(exception); if (showPageError) { pageError.value = true; errorMsg.value = msg; } else { SmartDialog.showToast(exceptionToString(msg)); } } String exceptionToString(Object exception) { return exception.toString().replaceAll("Exception:", ""); } void onLogin() {} void onLogout() {} } class BasePageController extends BaseController { final ScrollController scrollController = ScrollController(); final EasyRefreshController easyRefreshController = EasyRefreshController(); int currentPage = 1; int count = 0; int maxPage = 0; int pageSize = 24; var canLoadMore = false.obs; var list = [].obs; Future refreshData() async { currentPage = 1; list.value = []; await loadData(); } Future loadData() async { try { if (loadding) return; loadding = true; pageError.value = false; pageEmpty.value = false; notLogin.value = false; pageLoadding.value = currentPage == 1; var result = await getData(currentPage, pageSize); //是否可以加载更多 if (result.isNotEmpty) { currentPage++; canLoadMore.value = true; pageEmpty.value = false; } else { canLoadMore.value = false; if (currentPage == 1) { pageEmpty.value = true; } } // 赋值数据 if (currentPage == 1) { list.value = result; } else { list.addAll(result); } } catch (e) { handleError(e, showPageError: currentPage == 1); } finally { loadding = false; pageLoadding.value = false; } } Future> getData(int page, int pageSize) async { return []; } void scrollToTopOrRefresh() { if (scrollController.offset > 0) { scrollController.animateTo( 0, duration: const Duration(milliseconds: 200), curve: Curves.linear, ); } else { easyRefreshController.callRefresh(); } } } ================================================ FILE: simple_live_app/lib/app/custom_throttle.dart ================================================ /// 这个类的目的是简化 throttle 的操作,以便更好的理解代码 /// 主要作用:节流,如果在很短时间内都会调用同一个方法,除了第一个方法有用以外 /// 剩下的方法将会被舍弃,在 [eachDelayMilli] 时间后,才会允许下一次调用 /// 会保存一个方法,在最后还会调用一次,和普通的 throttle 不太一样 class DelayedThrottle { bool isInvoking = false; int eachDelayMilli; Future Function()? storeFunc; DelayedThrottle(this.eachDelayMilli); void invoke(Future Function() longCostFunc) { if (isInvoking) { storeFunc = longCostFunc; return; } storeFunc = null; isInvoking = true; longCostFunc().then((value) { Future.delayed(Duration(milliseconds: eachDelayMilli), () { isInvoking = false; if (storeFunc != null) { invoke(storeFunc!); } }); }); } } ================================================ FILE: simple_live_app/lib/app/event_bus.dart ================================================ import 'dart:async'; import 'package:simple_live_app/app/log.dart'; /// 全局事件 class EventBus { /// 点击了底部导航 static const String kBottomNavigationBarClicked = "BottomNavigationBarClicked"; static EventBus? _instance; static EventBus get instance { _instance ??= EventBus(); return _instance!; } final Map _streams = {}; /// 触发事件 void emit(String name, T data) { if (!_streams.containsKey(name)) { _streams.addAll({name: StreamController.broadcast()}); } Log.d("Emit Event:$name\r\n$data"); _streams[name]!.add(data); } /// 监听事件 StreamSubscription listen(String name, Function(dynamic)? onData) { if (!_streams.containsKey(name)) { _streams.addAll({name: StreamController.broadcast()}); } return _streams[name]!.stream.listen(onData); } } ================================================ FILE: simple_live_app/lib/app/log.dart ================================================ import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:intl/intl.dart'; import 'package:logger/logger.dart'; import 'package:path_provider/path_provider.dart'; import 'package:simple_live_app/app/utils.dart'; class Log { static LogFileWriter? logFileWriter; static void initWriter() { logFileWriter = LogFileWriter(); } static void disposeWriter() { logFileWriter?.close(); logFileWriter = null; } static void writeLog(content, [Level level = Level.info]) { logFileWriter ?.write("[${level.name.toUpperCase()}] $_currentTime:$content"); } static RxList debugLogs = [].obs; static void addDebugLog(String content, Color? color) { if (kReleaseMode) { return; } if (content.contains("请求响应")) { content = content.split("\n").join('\n💡 '); } try { debugLogs.insert(0, DebugLogModel(DateTime.now(), content, color: color)); } catch (e) { if (kDebugMode) { print(e); } } } static Logger logger = Logger( printer: PrettyPrinter( methodCount: 0, errorMethodCount: 8, lineLength: 120, colors: true, printEmojis: true, dateTimeFormat: DateTimeFormat.none, ), ); static void d(String message, [bool writeFile = true]) { addDebugLog(message, Colors.orange); logger.d("${DateTime.now().toString()}\n$message"); if (writeFile) { writeLog(message, Level.debug); } } static void i(String message, [bool writeFile = true]) { addDebugLog(message, Colors.blue); logger.i("${DateTime.now().toString()}\n$message"); if (writeFile) { logFileWriter?.write("[INFO] $_currentTime:$message"); writeLog(message, Level.info); } } static void e(String message, StackTrace stackTrace, [bool writeFile = true]) { addDebugLog('$message\r\n\r\n$stackTrace', Colors.red); logger.e("${DateTime.now().toString()}\n$message", stackTrace: stackTrace); if (writeFile) { writeLog("$message\n$stackTrace", Level.error); } } static void w(String message, [bool writeFile = true]) { addDebugLog(message, Colors.pink); logger.w("${DateTime.now().toString()}\n$message"); if (writeFile) { writeLog(message, Level.warning); } } static void logPrint(dynamic obj, [bool writeFile = true]) { addDebugLog(obj.toString(), Colors.red); if (writeFile) { writeLog(obj, Level.info); } //logger.e(obj.toString(), obj, obj?.stackTrace); if (kDebugMode) { print(obj); } } static String get _currentTime => Utils.timeFormat.format(DateTime.now()); } class LogFileWriter { late String fileName; LogFileWriter() { var dt = DateFormat("yyyy-MM-dd HH-mm-ss").format(DateTime.now()); fileName = "$dt.log"; initFile(); } IOSink? fileWriter; void initFile() async { var supportDir = await getApplicationSupportDirectory(); var logDir = Directory("${supportDir.path}/log"); if (!await logDir.exists()) { await logDir.create(); } var logFile = File("${logDir.path}/$fileName"); fileWriter = logFile.openWrite(mode: FileMode.append); writeSystemInfo(); } void write(String content) { fileWriter?.write(content); fileWriter?.write("\r\n"); } Future close() async { await fileWriter?.close(); } void writeSystemInfo() async { DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); write("System Info:"); write("Current Time: ${DateTime.now()}"); write("Platform: ${Platform.operatingSystem}"); write("Version: ${Platform.operatingSystemVersion}"); write("Local: ${Platform.localeName}"); write( "App Version: ${Utils.packageInfo.version}+${Utils.packageInfo.buildNumber}"); if (Platform.isAndroid) { write((await deviceInfo.androidInfo).data.toString()); } else if (Platform.isIOS) { write((await deviceInfo.iosInfo).data.toString()); } else if (Platform.isLinux) { write((await deviceInfo.linuxInfo).data.toString()); } else if (Platform.isMacOS) { write((await deviceInfo.macOsInfo).data.toString()); } else if (Platform.isWindows) { write((await deviceInfo.windowsInfo).data.toString()); } write("End System Info"); } } class DebugLogModel { final String content; final DateTime datetime; final Color? color; DebugLogModel(this.datetime, this.content, {this.color}); } ================================================ FILE: simple_live_app/lib/app/sites.dart ================================================ import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_core/simple_live_core.dart'; class Sites { static final Map allSites = { Constant.kBiliBili: Site( id: Constant.kBiliBili, logo: "assets/images/bilibili_2.png", name: "哔哩哔哩", liveSite: BiliBiliSite(), ), Constant.kDouyu: Site( id: Constant.kDouyu, logo: "assets/images/douyu.png", name: "斗鱼直播", liveSite: DouyuSite(), ), Constant.kHuya: Site( id: Constant.kHuya, logo: "assets/images/huya.png", name: "虎牙直播", liveSite: HuyaSite(), ), Constant.kDouyin: Site( id: Constant.kDouyin, logo: "assets/images/douyin.png", name: "抖音直播", liveSite: DouyinSite(), ), }; static List get supportSites { return AppSettingsController.instance.siteSort .map((key) => allSites[key]!) .toList(); } } class Site { final String id; final String name; final String logo; final LiveSite liveSite; Site({ required this.id, required this.liveSite, required this.logo, required this.name, }); } ================================================ FILE: simple_live_app/lib/app/utils/archive.dart ================================================ import 'dart:convert'; import 'dart:io'; import 'package:archive/archive_io.dart'; import 'package:path/path.dart'; extension ArchiveExt on Archive { addDirectoryToArchive(String dirPath, String parentPath) { final dir = Directory(dirPath); final entities = dir.listSync(recursive: false); for (final entity in entities) { final relativePath = relative(entity.path, from: parentPath); if (entity is File) { final data = entity.readAsBytesSync(); final archiveFile = ArchiveFile(relativePath, data.length, data); addFile(archiveFile); } else if (entity is Directory) { addDirectoryToArchive(entity.path, parentPath); } } } add(String name, T raw) { final data = json.encode(raw); addFile( // 这样会出现问题 不清楚原因 ArchiveFile.string(name, data) //ArchiveFile(name, data.length, data), ); } } ================================================ FILE: simple_live_app/lib/app/utils/document.dart ================================================ import 'dart:io'; import 'package:simple_live_app/app/log.dart'; // 扩展 Directory 类,添加清空文件夹的功能并验证是否为文件夹 extension DirectoryCleaner on Directory { Future clear() async { // 首先判断是否为文件夹 if (await exists() && await FileSystemEntity.isDirectory(path)) { // 列出文件夹中的所有文件和子文件夹 List files = listSync(); // 遍历文件列表并删除每个文件或子文件夹 for (FileSystemEntity file in files) { if (file is File) { await file.delete(); Log.i('删除文件: ${file.path}'); } else if (file is Directory) { await Directory(file.path).delete(recursive: true); Log.i('删除文件夹: ${file.path}'); } } Log.i('文件夹清空完成'); } else { Log.i('$path 不是一个有效的文件夹'); } } // 阻塞主线程 void clearSync() { if ( existsSync() && FileSystemEntity.isDirectorySync(path)) { List files = listSync(); for (FileSystemEntity file in files) { if (file is File) { file.deleteSync(); Log.i('删除文件: ${file.path}'); } else if (file is Directory) { Directory(file.path).deleteSync(recursive: true); Log.i('删除文件夹: ${file.path}'); } } Log.i('文件夹清空完成'); } else { Log.i('$path 不是一个有效的文件夹'); } } } ================================================ FILE: simple_live_app/lib/app/utils/listen_fourth_button.dart ================================================ import 'package:flutter/gestures.dart'; /// 鼠标侧键点击手势识别器 /// - https://github.com/flutter/flutter/issues/115641 /// - https://github.com/witnet/my-wit-wallet/pull/261 class FourthButtonTapGestureRecognizer extends BaseTapGestureRecognizer { GestureTapDownCallback? onTapDown; @override void handleTapDown({required PointerDownEvent down}) { final TapDownDetails details = TapDownDetails( globalPosition: down.position, localPosition: down.localPosition, kind: getKindForPointer(down.pointer), ); switch (down.buttons) { case 8: if (onTapDown != null) { invokeCallback('onTapDown', () => onTapDown!(details)); } break; default: } } @override void handleTapCancel( {required PointerDownEvent down, PointerCancelEvent? cancel, required String reason}) {} @override void handleTapUp( {required PointerDownEvent down, required PointerUpEvent up}) {} } ================================================ FILE: simple_live_app/lib/app/utils.dart ================================================ import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:intl/intl.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/log.dart'; typedef TextValidate = bool Function(String text); class Utils { static late PackageInfo packageInfo; static DateFormat dateFormat = DateFormat("MM-dd HH:mm"); static DateFormat dateFormatWithYear = DateFormat("yyyy-MM-dd HH:mm"); static DateFormat timeFormat = DateFormat("HH:mm:ss"); /// 处理时间 static String parseTime(DateTime? dt) { if (dt == null) { return ""; } var dtNow = DateTime.now(); if (dt.year == dtNow.year && dt.month == dtNow.month && dt.day == dtNow.day) { return "${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}"; } if (dt.year == dtNow.year) { return dateFormat.format(dt); } return dateFormatWithYear.format(dt); } /// 提示弹窗 /// - `content` 内容 /// - `title` 弹窗标题 /// - `confirm` 确认按钮内容,留空为确定 /// - `cancel` 取消按钮内容,留空为取消 static Future showAlertDialog( String content, { String title = '', String confirm = '', String cancel = '', bool selectable = false, List? actions, }) async { var result = await Get.dialog( AlertDialog( title: Text(title), content: Container( constraints: const BoxConstraints( maxHeight: 400, ), child: SingleChildScrollView( child: Padding( padding: AppStyle.edgeInsetsV12, child: selectable ? SelectableText(content) : Text(content), ), ), ), actions: [ ...?actions, TextButton( onPressed: (() => Get.back(result: false)), child: Text(cancel.isEmpty ? "取消" : cancel), ), TextButton( onPressed: (() => Get.back(result: true)), child: Text(confirm.isEmpty ? "确定" : confirm), ), ], ), ); return result ?? false; } /// 提示弹窗 /// - `content` 内容 /// - `title` 弹窗标题 /// - `confirm` 确认按钮内容,留空为确定 static Future showMessageDialog(String content, {String title = '', String confirm = '', bool selectable = false}) async { var result = await Get.dialog( AlertDialog( title: Text(title), content: Padding( padding: AppStyle.edgeInsetsV12, child: selectable ? SelectableText(content) : Text(content), ), actions: [ TextButton( onPressed: (() => Get.back(result: true)), child: Text(confirm.isEmpty ? "确定" : confirm), ), ], ), ); return result ?? false; } static void showRightDialog({ required String title, Function()? onDismiss, required Widget child, double width = 320, bool useSystem = false, }) { SmartDialog.show( alignment: Alignment.topRight, animationBuilder: (controller, child, animationParam) { //从右到左 return SlideTransition( position: Tween( begin: const Offset(1, 0), end: Offset.zero, ).animate(controller.view), child: child, ); }, useSystem: useSystem, maskColor: Colors.transparent, animationTime: const Duration(milliseconds: 200), builder: (context) => Container( width: width + MediaQuery.of(context).padding.right, padding: EdgeInsets.only(right: MediaQuery.of(context).padding.right), decoration: BoxDecoration( color: Get.theme.cardColor, borderRadius: const BorderRadius.only( topLeft: Radius.circular(4), bottomLeft: Radius.circular(4), ), ), child: SafeArea( left: false, right: false, child: MediaQuery( data: const MediaQueryData(padding: EdgeInsets.zero), child: Column( children: [ ListTile( visualDensity: VisualDensity.compact, contentPadding: EdgeInsets.zero, leading: IconButton( onPressed: () { SmartDialog.dismiss(status: SmartStatus.allCustom).then( (value) => onDismiss?.call(), ); }, icon: const Icon(Icons.arrow_back), ), title: Text( title, style: Get.textTheme.titleMedium, ), ), Divider( height: 1, color: Colors.grey.withAlpha(25), ), Expanded( child: child, ), ], ), ), ), ), ); } static void hideRightDialog() { SmartDialog.dismiss(status: SmartStatus.allCustom); } static Future showBottomSheet({ required String title, required Widget child, double maxWidth = 600, }) async { var result = await showModalBottomSheet( context: Get.context!, constraints: BoxConstraints( maxWidth: maxWidth, ), shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(12), topRight: Radius.circular(12), ), ), builder: (_) => Column( children: [ ListTile( contentPadding: const EdgeInsets.only( left: 12, ), title: Text(title), trailing: IconButton( onPressed: Get.back, icon: const Icon(Remix.close_line), ), ), Expanded( child: child, ), ], ), ); return result; } /// 文本编辑的弹窗 /// - `content` 编辑框默认的内容 /// - `title` 弹窗标题 /// - `confirm` 确认按钮内容 /// - `cancel` 取消按钮内容 static Future showEditTextDialog( String content, { String title = '', String? hintText, String confirm = '', String cancel = '', TextValidate? validate, }) async { final TextEditingController textEditingController = TextEditingController(text: content); var result = await Get.dialog( AlertDialog( title: Text(title), content: Padding( padding: AppStyle.edgeInsetsT12, child: TextField( controller: textEditingController, decoration: InputDecoration( border: const OutlineInputBorder(), //prefixText: title, contentPadding: AppStyle.edgeInsetsA12, hintText: hintText ?? title, ), // style: TextStyle( // height: 1.0, // color: Get.isDarkMode ? Colors.white : Colors.black), autofocus: true, ), ), actions: [ TextButton( onPressed: Get.back, child: const Text("取消"), ), TextButton( onPressed: () { if (validate != null && !validate(textEditingController.text)) { return; } Get.back(result: textEditingController.text); }, child: const Text("确定"), ), ], ), // barrierColor: // Get.isDarkMode ? Colors.grey.withOpacity(.3) : Colors.black38, ); return result; } static Future showOptionDialog( List contents, T value, { String title = '', }) async { var result = await Get.dialog( RadioGroup( groupValue: value, onChanged: (e) { Get.back(result: e); }, child: SimpleDialog( title: Text(title), children: contents .map( (e) => RadioListTile( title: Text(e.toString()), value: e, ), ) .toList(), ), ), ); return result; } /// 多段指引用户内容的弹窗 /// - `content` 内容:可滚动 /// - `title` 顶部弹窗标题 /// - `actions` 底部按钮 static Future showInformationHelpDialog({ required List content, Widget? title, List? actions, }) async { var result = await Get.dialog( AlertDialog( title: title ?? const Text("帮助"), scrollable: true, content: SingleChildScrollView(child: ListBody(children: content)), actions: actions ?? [ TextButton( onPressed: Get.back, child: const Text("确定"), ), ], ), ); return result; } static Future showStatement() async { var text = await rootBundle.loadString("assets/statement.txt"); var result = await showAlertDialog( text, selectable: true, title: "免责声明", confirm: "已阅读并同意", cancel: "退出", ); if (!result) { exit(0); } } static Future showMapOptionDialog( Map contents, T value, { String title = '', }) async { var result = await Get.dialog( RadioGroup( groupValue: value, onChanged: (e) { Get.back(result: e); }, child: SimpleDialog( title: Text(title), children: contents.keys .map( (e) => RadioListTile( title: Text((contents[e] ?? '-').tr), value: e, ), ) .toList(), ), ), ); return result; } static int parseVersion(String version) { var sp = version.split('.'); var num = ""; for (var item in sp) { num = num + item.padLeft(2, '0'); } return int.parse(num); } static String onlineToString(int num) { if (num >= 10000) { return "${(num / 10000.0).toStringAsFixed(1)}万"; } return num.toString(); } /// 检查相册权限 static Future checkPhotoPermission() async { try { if (!Platform.isIOS) { return true; } var status = await Permission.photos.status; if (status == PermissionStatus.granted) { return true; } status = await Permission.photos.request(); if (status.isGranted) { return true; } else { SmartDialog.showToast( "请授予相册访问权限", ); return false; } } catch (e) { return false; } } static final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); /// 检查文件权限 static Future checkStorgePermission() async { try { if (!Platform.isAndroid) { return true; } Permission permission = Permission.storage; var androidIndo = await deviceInfo.androidInfo; if (androidIndo.version.sdkInt >= 33) { permission = Permission.manageExternalStorage; } var status = await permission.status; if (status == PermissionStatus.granted) { return true; } status = await permission.request(); if (status.isGranted) { return true; } else { SmartDialog.showToast( "请授予文件访问权限", ); return false; } } catch (e) { return false; } } ///16进制颜色转换 static Color convertHexColor(String hexColor) { hexColor = hexColor.replaceAll("#", ""); if (hexColor.length == 4) { hexColor = "00$hexColor"; } if (hexColor.length == 6) { var R = int.parse(hexColor.substring(0, 2), radix: 16); var G = int.parse(hexColor.substring(2, 4), radix: 16); var B = int.parse(hexColor.substring(4, 6), radix: 16); return Color.fromARGB(255, R, G, B); } if (hexColor.length == 8) { var A = int.parse(hexColor.substring(0, 2), radix: 16); var R = int.parse(hexColor.substring(2, 4), radix: 16); var G = int.parse(hexColor.substring(4, 6), radix: 16); var B = int.parse(hexColor.substring(6, 8), radix: 16); return Color.fromARGB(A, R, G, B); } return Colors.white; } /// 复制内容到剪贴板 static void copyToClipboard(String text) async { try { await Clipboard.setData(ClipboardData(text: text)); SmartDialog.showToast("已复制到剪贴板"); } catch (e) { Log.logPrint(e); SmartDialog.showToast("复制到剪贴板失败: $e"); } } /// 获取剪贴板内容 static Future getClipboard() async { try { var content = await Clipboard.getData(Clipboard.kTextPlain); if (content == null) { SmartDialog.showToast("无法读取剪贴板内容"); return null; } return content.text; } catch (e) { Log.logPrint(e); SmartDialog.showToast("读取剪切板内容失败:$e"); } return null; } static bool isRegexFormat(String keyword) { return keyword.startsWith('/') && keyword.endsWith('/') && keyword.length > 2; } static String removeRegexFormat(String keyword) { return keyword.substring(1, keyword.length - 1); } static String parseFileSize(int size) { if (size < 1024) { return "$size B"; } if (size < 1024 * 1024) { return "${(size / 1024).toStringAsFixed(2)} KB"; } if (size < 1024 * 1024 * 1024) { return "${(size / 1024 / 1024).toStringAsFixed(2)} MB"; } return "${(size / 1024 / 1024 / 1024).toStringAsFixed(2)} GB"; } } ================================================ FILE: simple_live_app/lib/main.dart ================================================ import 'dart:async'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:logger/logger.dart'; import 'package:media_kit/media_kit.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:path_provider/path_provider.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/app/utils/listen_fourth_button.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:simple_live_app/modules/other/debug_log_page.dart'; import 'package:simple_live_app/routes/app_pages.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/douyin_account_service.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:simple_live_app/services/follow_service.dart'; import 'package:simple_live_app/services/local_storage_service.dart'; import 'package:simple_live_app/services/sync_service.dart'; import 'package:simple_live_app/widgets/status/app_loadding_widget.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:window_manager/window_manager.dart'; import 'package:path/path.dart' as p; import 'package:dynamic_color/dynamic_color.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await migrateData(); await initWindow(); MediaKit.ensureInitialized(); await Hive.initFlutter( (!Platform.isAndroid && !Platform.isIOS) ? (await getApplicationSupportDirectory()).path : null, ); //初始化服务 await initServices(); SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); //设置状态栏为透明 SystemUiOverlayStyle systemUiOverlayStyle = const SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, systemNavigationBarColor: Colors.transparent, ); SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); runApp(const MyApp()); } /// 将Hive数据迁移到Application Support Future migrateData() async { if (Platform.isAndroid || Platform.isIOS) { return; } var hiveFileList = [ "followuser", //旧版本写错成hostiry了 "hostiry", "followusertag", "localstorage", "danmushield", ]; try { var newDir = await getApplicationSupportDirectory(); var hiveFile = File(p.join(newDir.path, "followuser.hive")); if (await hiveFile.exists()) { return; } var oldDir = await getApplicationDocumentsDirectory(); for (var element in hiveFileList) { var oldFile = File(p.join(oldDir.path, "$element.hive")); if (await oldFile.exists()) { var fileName = "$element.hive"; if (element == "hostiry") { fileName = "history.hive"; } await oldFile.copy(p.join(newDir.path, fileName)); await oldFile.delete(); } var lockFile = File(p.join(oldDir.path, "$element.lock")); if (await lockFile.exists()) { await lockFile.delete(); } } } catch (e) { Log.logPrint(e); } } Future initWindow() async { if (!(Platform.isMacOS || Platform.isWindows || Platform.isLinux)) { return; } await windowManager.ensureInitialized(); WindowOptions windowOptions = const WindowOptions( minimumSize: Size(280, 280), center: true, title: "Simple Live", ); windowManager.waitUntilReadyToShow(windowOptions, () async { await windowManager.show(); await windowManager.focus(); }); } Future initServices() async { Hive.registerAdapter(FollowUserAdapter()); Hive.registerAdapter(HistoryAdapter()); Hive.registerAdapter(FollowUserTagAdapter()); //包信息 Utils.packageInfo = await PackageInfo.fromPlatform(); //本地存储 Log.d("Init LocalStorage Service"); await Get.put(LocalStorageService()).init(); await Get.put(DBService()).init(); //初始化设置控制器 Get.put(AppSettingsController()); Get.put(BiliBiliAccountService()); Get.put(DouyinAccountService()); Get.put(SyncService()); Get.put(FollowService()); initCoreLog(); } void initCoreLog() { //日志信息 CoreLog.enableLog = !kReleaseMode || AppSettingsController.instance.logEnable.value; CoreLog.requestLogType = RequestLogType.short; CoreLog.onPrintLog = (level, msg) { switch (level) { case Level.debug: Log.d(msg); break; case Level.error: Log.e(msg, StackTrace.current); break; case Level.info: Log.i(msg); break; case Level.warning: Log.w(msg); break; default: Log.logPrint(msg); } }; } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { bool isDynamicColor = AppSettingsController.instance.isDynamic.value; Color styleColor = Color(AppSettingsController.instance.styleColor.value); return DynamicColorBuilder( builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) { ColorScheme? lightColorScheme; ColorScheme? darkColorScheme; if (lightDynamic != null && darkDynamic != null && isDynamicColor) { lightColorScheme = lightDynamic; darkColorScheme = darkDynamic; } else { lightColorScheme = ColorScheme.fromSeed( seedColor: styleColor, brightness: Brightness.light, ); darkColorScheme = ColorScheme.fromSeed( seedColor: styleColor, brightness: Brightness.dark); } return GetMaterialApp( title: "Simple Live", theme: AppStyle.lightTheme.copyWith(colorScheme: lightColorScheme), darkTheme: AppStyle.darkTheme.copyWith(colorScheme: darkColorScheme), themeMode: ThemeMode.values[Get.find().themeMode.value], initialRoute: RoutePath.kIndex, getPages: AppPages.routes, //国际化 locale: const Locale("zh", "CN"), localizationsDelegates: const [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [Locale("zh", "CN")], logWriterCallback: (text, {bool? isError}) { Log.addDebugLog(text, (isError ?? false) ? Colors.red : Colors.grey); Log.writeLog(text, (isError ?? false) ? Level.error : Level.info); }, // 升级后Android页面过渡动画似乎有BUG defaultTransition: Platform.isAndroid ? Transition.cupertino : null, //debugShowCheckedModeBanner: false, navigatorObservers: [FlutterSmartDialog.observer], builder: FlutterSmartDialog.init( loadingBuilder: ((msg) => const AppLoaddingWidget()), //字体大小不跟随系统变化 builder: (context, child) { // Fix for HyperOS windowed-mode Flutter bug: // - Values > 50 indicate the bug (windowed mode on HyperOS) // - Values == 0 are valid for fullscreen/immersive mode and must NOT be treated as abnormal const fallbackPadding = EdgeInsets.only(top: 25, bottom: 35); const maxNormalPadding = 50.0; final mediaQueryData = MediaQuery.of(context); final hasAbnormalPadding = mediaQueryData.viewPadding.top > maxNormalPadding; final fixedMediaQueryData = hasAbnormalPadding ? mediaQueryData.copyWith( viewPadding: fallbackPadding, padding: fallbackPadding, textScaler: const TextScaler.linear(1.0), ) : mediaQueryData.copyWith(textScaler: const TextScaler.linear(1.0)); return MediaQuery( data: fixedMediaQueryData, child: Stack( children: [ //侧键返回 RawGestureDetector( excludeFromSemantics: true, gestures: { FourthButtonTapGestureRecognizer: GestureRecognizerFactoryWithHandlers< FourthButtonTapGestureRecognizer>( () => FourthButtonTapGestureRecognizer(), (FourthButtonTapGestureRecognizer instance) { instance.onTapDown = (TapDownDetails details) async { //如果处于全屏状态,退出全屏 if (!Platform.isAndroid && !Platform.isIOS) { if (await windowManager.isFullScreen()) { await windowManager.setFullScreen(false); return; } } Get.back(); }; }, ), }, child: KeyboardListener( focusNode: FocusNode(), onKeyEvent: (KeyEvent event) async { if (event is KeyDownEvent && event.logicalKey == LogicalKeyboardKey.escape) { // ESC退出全屏 // 如果处于全屏状态,退出全屏 if (!Platform.isAndroid && !Platform.isIOS) { if (await windowManager.isFullScreen()) { await windowManager.setFullScreen(false); return; } } } }, child: child!, ), ), //查看DEBUG日志按钮 //只在Debug、Profile模式显示 Visibility( visible: !kReleaseMode, child: Positioned( right: 12, bottom: 100 + context.mediaQueryViewPadding.bottom, child: Opacity( opacity: 0.4, child: ElevatedButton( child: const Text("DEBUG LOG"), onPressed: () { Get.bottomSheet( const DebugLogPage(), ); }, ), ), ), ), ], ), ); }, ), ); })); } } ================================================ FILE: simple_live_app/lib/models/account/bilibili_user_info_page.dart ================================================ import 'dart:convert'; T? asT(dynamic value) { if (value is T) { return value; } return null; } class BiliBiliUserInfoModel { BiliBiliUserInfoModel({ this.mid, this.uname, this.userid, this.sign, this.birthday, this.sex, this.nickFree, this.rank, }); factory BiliBiliUserInfoModel.fromJson(Map json) => BiliBiliUserInfoModel( mid: asT(json['mid']), uname: asT(json['uname']), userid: asT(json['userid']), sign: asT(json['sign']), birthday: asT(json['birthday']), sex: asT(json['sex']), nickFree: asT(json['nick_free']), rank: asT(json['rank']), ); int? mid; String? uname; String? userid; String? sign; String? birthday; String? sex; bool? nickFree; String? rank; @override String toString() { return jsonEncode(this); } Map toJson() => { 'mid': mid, 'uname': uname, 'userid': userid, 'sign': sign, 'birthday': birthday, 'sex': sex, 'nick_free': nickFree, 'rank': rank, }; } ================================================ FILE: simple_live_app/lib/models/db/follow_user.dart ================================================ import 'package:get/get.dart'; import 'package:hive/hive.dart'; part 'follow_user.g.dart'; @HiveType(typeId: 1) class FollowUser { FollowUser({ required this.id, required this.roomId, required this.siteId, required this.userName, required this.face, required this.addTime, this.tag = "全部" }); ///id=siteId_roomId @HiveField(0) String id; @HiveField(1) String roomId; @HiveField(2) String siteId; @HiveField(3) String userName; @HiveField(4) String face; @HiveField(5) DateTime addTime; @HiveField(6) String tag; /// 直播状态 /// 0=未知(加载中) 1=未开播 2=直播中 Rx liveStatus = 0.obs; /// 开播时间戳 String? liveStartTime; factory FollowUser.fromJson(Map json) => FollowUser( id: json['id'], roomId: json['roomId'], siteId: json['siteId'], userName: json['userName'], face: json['face'], addTime: DateTime.parse(json['addTime']), tag: json["tag"]??"全部", ); Map toJson() => { 'id': id, 'roomId': roomId, 'siteId': siteId, 'userName': userName, 'face': face, 'addTime': addTime.toString(), 'tag':tag, }; } ================================================ FILE: simple_live_app/lib/models/db/follow_user.g.dart ================================================ // GENERATED CODE - DO NOT MODIFY BY HAND part of 'follow_user.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** class FollowUserAdapter extends TypeAdapter { @override final int typeId = 1; @override FollowUser read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return FollowUser( id: fields[0] as String, roomId: fields[1] as String, siteId: fields[2] as String, userName: fields[3] as String, face: fields[4] as String, addTime: fields[5] as DateTime, tag: fields[6] ?? "全部", ); } @override void write(BinaryWriter writer, FollowUser obj) { writer ..writeByte(7) ..writeByte(0) ..write(obj.id) ..writeByte(1) ..write(obj.roomId) ..writeByte(2) ..write(obj.siteId) ..writeByte(3) ..write(obj.userName) ..writeByte(4) ..write(obj.face) ..writeByte(5) ..write(obj.addTime) ..writeByte(6) ..write(obj.tag); } @override int get hashCode => typeId.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is FollowUserAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } ================================================ FILE: simple_live_app/lib/models/db/follow_user_tag.dart ================================================ import 'package:hive/hive.dart'; part 'follow_user_tag.g.dart'; @HiveType(typeId: 3) class FollowUserTag { @HiveField(1) String id; // 用户自定义tag @HiveField(2) String tag; // followUserId @HiveField(3) List userId; FollowUserTag({ required this.id, required this.tag, required this.userId, }); factory FollowUserTag.fromJson(Map json) { return FollowUserTag( id: json['id'], tag: json['tag'], userId: List.from(json['userId']), ); } Map toJson() { return { 'id': id, 'tag': tag, 'userId': userId, }; } FollowUserTag copyWith({ String? id, String? tag, List? userId, }) { return FollowUserTag( id: id ?? this.id, tag: tag ?? this.tag, userId: userId ?? this.userId, ); } } ================================================ FILE: simple_live_app/lib/models/db/follow_user_tag.g.dart ================================================ // GENERATED CODE - DO NOT MODIFY BY HAND part of 'follow_user_tag.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** class FollowUserTagAdapter extends TypeAdapter { @override final int typeId = 3; @override FollowUserTag read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return FollowUserTag( id: fields[1] as String, tag: fields[2] as String, userId: (fields[3] as List).cast(), ); } @override void write(BinaryWriter writer, FollowUserTag obj) { writer ..writeByte(3) ..writeByte(1) ..write(obj.id) ..writeByte(2) ..write(obj.tag) ..writeByte(3) ..write(obj.userId); } @override int get hashCode => typeId.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is FollowUserTagAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } ================================================ FILE: simple_live_app/lib/models/db/history.dart ================================================ import 'package:hive/hive.dart'; part 'history.g.dart'; @HiveType(typeId: 2) class History { History({ required this.id, required this.roomId, required this.siteId, required this.userName, required this.face, required this.updateTime, }); ///id=siteId_roomId @HiveField(0) String id; @HiveField(1) String roomId; @HiveField(2) String siteId; @HiveField(3) String userName; @HiveField(4) String face; @HiveField(5) DateTime updateTime; factory History.fromJson(Map json) => History( id: json["id"], roomId: json["roomId"], siteId: json["siteId"], userName: json["userName"], face: json["face"], updateTime: DateTime.parse(json["updateTime"]), ); Map toJson() => { "id": id, "roomId": roomId, "siteId": siteId, "userName": userName, "face": face, "updateTime": updateTime.toString(), }; } ================================================ FILE: simple_live_app/lib/models/db/history.g.dart ================================================ // GENERATED CODE - DO NOT MODIFY BY HAND part of 'history.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** class HistoryAdapter extends TypeAdapter { @override final int typeId = 2; @override History read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return History( id: fields[0] as String, roomId: fields[1] as String, siteId: fields[2] as String, userName: fields[3] as String, face: fields[4] as String, updateTime: fields[5] as DateTime, ); } @override void write(BinaryWriter writer, History obj) { writer ..writeByte(6) ..writeByte(0) ..write(obj.id) ..writeByte(1) ..write(obj.roomId) ..writeByte(2) ..write(obj.siteId) ..writeByte(3) ..write(obj.userName) ..writeByte(4) ..write(obj.face) ..writeByte(5) ..write(obj.updateTime); } @override int get hashCode => typeId.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is HistoryAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } ================================================ FILE: simple_live_app/lib/models/follow_user_item.dart ================================================ ================================================ FILE: simple_live_app/lib/models/sync_client_info_model.dart ================================================ import 'dart:convert'; T? asT(dynamic value) { if (value is T) { return value; } return null; } class SyncClientInfoModel { SyncClientInfoModel({ required this.name, required this.version, required this.address, required this.port, required this.type, }); factory SyncClientInfoModel.fromJson(Map json) => SyncClientInfoModel( type: asT(json['type'])!, name: asT(json['name'])!, version: asT(json['version'])!, address: asT(json['address'])!, port: asT(json['port'])!, ); String type; String name; String version; String address; int port; @override String toString() { return jsonEncode(this); } Map toJson() => { 'name': name, 'version': version, 'address': address, 'port': port, 'type': type, }; } ================================================ FILE: simple_live_app/lib/models/version_model.dart ================================================ import 'dart:convert'; T? asT(dynamic value) { if (value is T) { return value; } return null; } class VersionModel { VersionModel({ required this.version, required this.versionNum, required this.versionDesc, required this.downloadUrl, }); factory VersionModel.fromJson(Map json) => VersionModel( version: asT(json['version'])!, versionNum: asT(json['version_num'])!, versionDesc: asT(json['version_desc'])!, downloadUrl: asT(json['download_url'])!, ); String version; int versionNum; String versionDesc; String downloadUrl; @override String toString() { return jsonEncode(this); } Map toJson() => { 'version': version, 'version_num': versionNum, 'version_desc': versionDesc, 'download_url': downloadUrl, }; } ================================================ FILE: simple_live_app/lib/modules/category/category_controller.dart ================================================ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/category/category_list_controller.dart'; class CategoryController extends GetxController with GetSingleTickerProviderStateMixin { late TabController tabController; CategoryController() { tabController = TabController(length: Sites.supportSites.length, vsync: this); } StreamSubscription? streamSubscription; @override void onInit() { streamSubscription = EventBus.instance.listen( EventBus.kBottomNavigationBarClicked, (index) { if (index == 2) { refreshOrScrollTop(); } }, ); for (var site in Sites.supportSites) { Get.put(CategoryListController(site), tag: site.id); } super.onInit(); } void refreshOrScrollTop() { var tabIndex = tabController.index; BasePageController controller; controller = Get.find(tag: Sites.supportSites[tabIndex].id); controller.scrollToTopOrRefresh(); } @override void onClose() { streamSubscription?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/category/category_list_controller.dart ================================================ import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_core/simple_live_core.dart'; class CategoryListController extends BasePageController { final Site site; CategoryListController(this.site); @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.getCategores(); return result.map((e) => AppLiveCategory.fromLiveCategory(e)).toList(); } } class AppLiveCategory extends LiveCategory { var showAll = false.obs; AppLiveCategory({ required super.id, required super.name, required super.children, }) { showAll.value = children.length < 19; } List get take15 => children.take(15).toList(); factory AppLiveCategory.fromLiveCategory(LiveCategory item) { return AppLiveCategory( children: item.children, id: item.id, name: item.name, ); } } ================================================ FILE: simple_live_app/lib/modules/category/category_list_view.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/category/category_list_controller.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/widgets/keep_alive_wrapper.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'package:simple_live_app/widgets/shadow_card.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:sticky_headers/sticky_headers.dart'; class CategoryListView extends StatelessWidget { final String tag; const CategoryListView(this.tag, {Key? key}) : super(key: key); CategoryListController get controller => Get.find(tag: tag); @override Widget build(BuildContext context) { return KeepAliveWrapper( child: Obx( () => EasyRefresh( firstRefresh: true, controller: controller.easyRefreshController, onRefresh: controller.refreshData, header: MaterialHeader( completeDuration: const Duration(milliseconds: 400), ), child: ListView.builder( padding: AppStyle.edgeInsetsA12, itemCount: controller.list.length, controller: controller.scrollController, itemBuilder: (_, i) { var item = controller.list[i]; return Column( children: [ StickyHeader( header: Container( padding: AppStyle.edgeInsetsV8.copyWith(left: 4), color: Theme.of(context).scaffoldBackgroundColor, alignment: Alignment.centerLeft, child: Text( item.name, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold), ), ), content: Obx( () => GridView.count( shrinkWrap: true, padding: AppStyle.edgeInsetsV8, physics: const NeverScrollableScrollPhysics(), crossAxisCount: MediaQuery.of(context).size.width ~/ 80, crossAxisSpacing: 8, mainAxisSpacing: 8, children: item.showAll.value ? (item.children .map( (e) => buildSubCategory(e), ) .toList()) : (item.take15 .map( (e) => buildSubCategory(e), ) .toList() ..add(buildShowMore(item))), ), ), ), ], ); }, ), ), ), ); } Widget buildSubCategory(LiveSubCategory item) { return ShadowCard( onTap: () { AppNavigator.toCategoryDetail(site: controller.site, category: item); }, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ NetImage( item.pic ?? "", width: 40, height: 40, borderRadius: 8, ), AppStyle.vGap4, Text( item.name, maxLines: 1, textAlign: TextAlign.center, style: const TextStyle(fontSize: 12), ), ], ), ); } Widget buildShowMore(AppLiveCategory item) { return ShadowCard( onTap: () { item.showAll.value = true; }, child: const Center( child: Text( "显示全部", maxLines: 1, textAlign: TextAlign.center, style: TextStyle(fontSize: 12), ), ), ); } } ================================================ FILE: simple_live_app/lib/modules/category/category_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/category/category_controller.dart'; import 'package:simple_live_app/modules/category/category_list_view.dart'; class CategoryPage extends GetView { const CategoryPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( titleSpacing: 8, title: TabBar( controller: controller.tabController, padding: EdgeInsets.zero, tabAlignment: TabAlignment.center, tabs: Sites.supportSites .map( (e) => Tab( //text: e.name, child: Row( children: [ Image.asset( e.logo, width: 24, ), AppStyle.hGap8, Text(e.name), ], ), ), ) .toList(), labelPadding: AppStyle.edgeInsetsH20, isScrollable: true, indicatorSize: TabBarIndicatorSize.label, ), ), body: TabBarView( controller: controller.tabController, children: Sites.supportSites .map( (e) => CategoryListView( e.id, ), ) .toList(), ), ); } } ================================================ FILE: simple_live_app/lib/modules/category/detail/category_detail_controller.dart ================================================ import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_core/simple_live_core.dart'; class CategoryDetailController extends BasePageController { final Site site; final LiveSubCategory subCategory; CategoryDetailController({ required this.site, required this.subCategory, }); @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.getCategoryRooms(subCategory, page: page); return result.items; } } ================================================ FILE: simple_live_app/lib/modules/category/detail/category_detail_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/category/detail/category_detail_controller.dart'; import 'package:simple_live_app/widgets/keep_alive_wrapper.dart'; import 'package:simple_live_app/widgets/live_room_card.dart'; import 'package:simple_live_app/widgets/page_grid_view.dart'; class CategoryDetailPage extends GetView { const CategoryDetailPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { var c = MediaQuery.of(context).size.width ~/ 200; if (c < 2) { c = 2; } return Scaffold( appBar: AppBar( title: Text(controller.subCategory.name), ), body: KeepAliveWrapper( child: PageGridView( pageController: controller, padding: AppStyle.edgeInsetsA12, firstRefresh: true, mainAxisSpacing: 12, crossAxisSpacing: 12, crossAxisCount: c, itemBuilder: (_, i) { var item = controller.list[i]; return LiveRoomCard(controller.site, item); }, ), ), ); } } ================================================ FILE: simple_live_app/lib/modules/follow_user/follow_user_controller.dart ================================================ // ignore_for_file: invalid_use_of_protected_member import 'dart:async'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:simple_live_app/services/follow_service.dart'; class FollowUserController extends BasePageController { StreamSubscription? onUpdatedIndexedStream; StreamSubscription? onUpdatedListStream; /// 0:全部 1:直播中 2:未直播 var filterMode = FollowUserTag(id: "0", tag: "全部", userId: []).obs; RxList tagList = [ FollowUserTag(id: "0", tag: "全部", userId: []), FollowUserTag(id: "1", tag: "直播中", userId: []), FollowUserTag(id: "2", tag: "未开播", userId: []), ].obs; // 用户自定义标签 RxList userTagList = [].obs; @override void onInit() { onUpdatedIndexedStream = EventBus.instance.listen( EventBus.kBottomNavigationBarClicked, (index) { if (index == 1) { scrollToTopOrRefresh(); } }, ); onUpdatedListStream = FollowService.instance.updatedListStream.listen((event) { filterData(); }); super.onInit(); } @override Future refreshData() async { await FollowService.instance.loadData(); updateTagList(); super.refreshData(); } @override Future> getData(int page, int pageSize) async { if (page > 1) { return Future.value([]); } if (filterMode.value.tag == "全部") { return FollowService.instance.followList.value; } else if (filterMode.value.tag == "直播中") { return FollowService.instance.liveList.value; } else if (filterMode.value.tag == "未开播") { return FollowService.instance.notLiveList.value; } else { FollowService.instance.filterDataByTag(filterMode.value); return FollowService.instance.curTagFollowList.value; } } void updateTagList() { userTagList.assignAll(FollowService.instance.followTagList); tagList.value = tagList.take(3).toList(); for (var i in userTagList) { if (!tagList.contains(i)) { tagList.add(i); } } } void filterData() { if (filterMode.value.tag == "全部") { list.assignAll(FollowService.instance.followList.value); } else if (filterMode.value.tag == "直播中") { list.assignAll(FollowService.instance.liveList.value); } else if (filterMode.value.tag == "未开播") { list.assignAll(FollowService.instance.notLiveList.value); } else { FollowService.instance.filterDataByTag(filterMode.value); list.assignAll(FollowService.instance.curTagFollowList); } } void setFilterMode(FollowUserTag tag) { filterMode.value = tag; filterData(); } void removeItem(FollowUser item) async { var result = await Utils.showAlertDialog("确定要取消关注${item.userName}吗?", title: "取消关注"); if (!result) { return; } // 取消关注同时删除标签内的 userId if(item.tag != "全部"){ var tag = tagList.firstWhere((tag) => tag.tag == item.tag); tag.userId.remove(item.id); updateTag(tag); } await DBService.instance.followBox.delete(item.id); refreshData(); } void updateItem(FollowUser item){ FollowService.instance.addFollow(item); } // 修改item的标签 void setItemTag(FollowUser item, FollowUserTag targetTag) { FollowUserTag tarTag = targetTag; FollowUserTag curTag = tagList.firstWhere((tag) => tag.tag == item.tag); // 从当前标签(非全部)删除item 向目标标签(全部包含所有item == 非全部)添加item curTag.userId.remove(item.id); tarTag.userId.addIf(!tarTag.userId.contains(item.id), item.id); // 数据库更新 item.tag = tarTag.tag; updateTag(curTag); updateTag(tarTag); updateItem(item); filterData(); } Future removeTag(FollowUserTag tag) async { // 将tag下的所有follow设置为全部 for(var i in tag.userId){ var follow = DBService.instance.followBox.get(i); if(follow != null){ follow.tag = "全部"; updateItem(follow); } } await FollowService.instance.delFollowUserTag(tag); updateTagList(); Log.i('删除tag${tag.tag}'); } void addTag(String tag) async { FollowService.instance .addFollowUserTag(tag) .then((value) => updateTagList()); } void updateTag(FollowUserTag followUserTag) { if(followUserTag.tag == '全部'){ return; } FollowService.instance.updateFollowUserTag(followUserTag); } void updateTagName(FollowUserTag followUserTag, String newTagName) { // 未操作 if (followUserTag.tag == newTagName) { return; } // 避免重名 if (tagList.any((item) => item.tag == newTagName)) { SmartDialog.showToast("标签名重复,修改失败"); return; } final FollowUserTag newTag = followUserTag.copyWith(tag: newTagName); updateTag(newTag); // update item's tag when update tagName for(var i in newTag.userId){ var follow = DBService.instance.followBox.get(i); if(follow != null){ follow.tag = newTagName; updateItem(follow); } } SmartDialog.showToast("标签名修改成功"); updateTagList(); } // 调整标签顺序 void updateTagOrder(int oldIndex, int newIndex) { if (newIndex > oldIndex) newIndex -= 1; // 处理索引调整 final item = userTagList.removeAt(oldIndex); userTagList.insert(newIndex, item); tagList.value = tagList.take(3).toList(); tagList.addAll(userTagList); DBService.instance.updateFollowTagOrder(userTagList); } @override void onClose() { onUpdatedIndexedStream?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/follow_user/follow_user_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/modules/follow_user/follow_user_controller.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/services/follow_service.dart'; import 'package:simple_live_app/widgets/filter_button.dart'; import 'package:simple_live_app/widgets/follow_user_item.dart'; import 'package:simple_live_app/widgets/page_grid_view.dart'; class FollowUserPage extends GetView { const FollowUserPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { var count = MediaQuery.of(context).size.width ~/ 500; if (count < 1) count = 1; return Scaffold( appBar: AppBar( title: const Text("关注用户"), actions: [ PopupMenuButton( itemBuilder: (context) { return const [ PopupMenuItem( value: 0, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Remix.save_2_line), AppStyle.hGap12, Text("导出文件") ], ), ), PopupMenuItem( value: 1, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Remix.folder_open_line), AppStyle.hGap12, Text("导入文件") ], ), ), PopupMenuItem( value: 2, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Remix.text), AppStyle.hGap12, Text("导出文本"), ], ), ), PopupMenuItem( value: 3, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Remix.file_text_line), AppStyle.hGap12, Text("导入文本"), ], ), ), PopupMenuItem( value: 4, child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Remix.price_tag_line), AppStyle.hGap12, Text("标签管理"), ], ), ), ]; }, onSelected: (value) { if (value == 0) { FollowService.instance.exportFile(); } else if (value == 1) { FollowService.instance.inputFile(); } else if (value == 2) { FollowService.instance.exportText(); } else if (value == 3) { FollowService.instance.inputText(); } else if (value == 4) { showTagsManager(); } }, ), ], leading: Obx( () => FollowService.instance.updating.value ? const IconButton( onPressed: null, icon: SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, ), ), ) : IconButton( onPressed: () { controller.refreshData(); }, icon: const Icon(Icons.refresh), ), ), ), body: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: AppStyle.edgeInsetsL8, child: Row( children: [ Expanded( child: Obx( () => SingleChildScrollView( scrollDirection: Axis.horizontal, child: Wrap( spacing: 12, children: controller.tagList.map((option) { return FilterButton( text: option.tag, selected: controller.filterMode.value == option, onTap: () { controller.setFilterMode(option); }, ); }).toList()), ), ), ), ], ), ), Expanded( child: PageGridView( crossAxisSpacing: 12, crossAxisCount: count, pageController: controller, firstRefresh: true, showPCRefreshButton: false, itemBuilder: (_, i) { var item = controller.list[i]; var site = Sites.allSites[item.siteId]!; return FollowUserItem( item: item, onRemove: () { controller.removeItem(item); }, onTap: () { AppNavigator.toLiveRoomDetail( site: site, roomId: item.roomId); }, onLongPress: () { setFollowTagDialog(item); }, ); }, ), ), ], ), ); } void setFollowTagDialog(FollowUser item) { /// 控制单选ui List copiedList = [ controller.tagList.first, ...controller.tagList.skip(3), ]; Rx checkTag = controller.tagList.indexOf(controller.filterMode.value) < 3 ? copiedList.first.obs : controller.filterMode.value.obs; final ScrollController scrollController = ScrollController(); Get.dialog( AlertDialog( contentPadding: const EdgeInsets.all(16.0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), content: Column( mainAxisSize: MainAxisSize.min, children: [ // 标题栏 Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( '设置标签', style: TextStyle( fontSize: 18, ), ), IconButton( icon: const Icon( Icons.check, ), onPressed: () { controller.setItemTag(item, checkTag.value); Get.back(); }, ), ], ), const Divider(), Obx( () { int selectedIndex = copiedList.indexOf(checkTag.value); WidgetsBinding.instance.addPostFrameCallback((_) { if (selectedIndex >= 0) { scrollController.animateTo( selectedIndex * 60.0, // 假设每项高度为 60 duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, ); } }); return SizedBox( height: 300, width: 300, child: RadioGroup( groupValue: checkTag.value, onChanged: (value) { checkTag.value = value!; }, child: ListView.builder( controller: scrollController, itemCount: copiedList.length, itemBuilder: (context, index) { var tagItem = copiedList[index]; return Container( decoration: BoxDecoration( border: Border( bottom: BorderSide( color: Colors.grey.shade300, width: 1.0), ), ), child: RadioListTile( title: Text(tagItem.tag), value: tagItem, ), ); }, ), ), ); }, ), ], ), ), ); } void showTagsManager() { Utils.showBottomSheet( title: '标签管理', child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ AppStyle.divider, ListTile( title: const Text("添加标签"), leading: const Icon(Icons.add), onTap: () { editTagDialog("添加标签"); }, ), AppStyle.divider, // 列表内容 Expanded( child: Obx( () => ReorderableListView.builder( itemCount: controller.userTagList.length, itemBuilder: (context, index) { // 偏移 FollowUserTag item = controller.userTagList[index]; return ListTile( key: ValueKey(item.id), title: GestureDetector( child: Text(item.tag), onLongPress: () { { editTagDialog("修改标签", followUserTag: item); } }, ), leading: IconButton( icon: const Icon(Icons.delete), onPressed: () { controller.removeTag(item); }, ), ); }, onReorder: (int oldIndex, int newIndex) { controller.updateTagOrder(oldIndex, newIndex); }, ), ), ), ]), ); } void editTagDialog(String title, {FollowUserTag? followUserTag}) { final TextEditingController tagEditController = TextEditingController(text: followUserTag?.tag); bool upMode = title == "添加标签" ? true : false; Get.dialog( AlertDialog( contentPadding: const EdgeInsets.all(16.0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12.0), ), content: SingleChildScrollView( padding: EdgeInsets.only( bottom: MediaQuery.of(Get.context!).viewInsets.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( title, style: const TextStyle( fontSize: 18, ), ), TextField( controller: tagEditController, minLines: 1, maxLines: 1, decoration: InputDecoration( border: const OutlineInputBorder(), contentPadding: AppStyle.edgeInsetsA12, enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.grey.withAlpha(51), ), ), ), onSubmitted: (tag) { upMode ? controller.addTag(tagEditController.text) : controller.updateTagName( followUserTag!, tagEditController.text); Get.back(); }, ), Container( margin: AppStyle.edgeInsetsB4, width: double.infinity, child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { Get.back(); }, child: const Text('否'), ), TextButton( onPressed: () { upMode ? controller.addTag(tagEditController.text) : controller.updateTagName( followUserTag!, tagEditController.text); Get.back(); }, child: const Text('是'), ), ], ), ) ], ), ), ), ); } } ================================================ FILE: simple_live_app/lib/modules/home/home_controller.dart ================================================ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/home/home_list_controller.dart'; import 'package:simple_live_app/routes/route_path.dart'; class HomeController extends GetxController with GetSingleTickerProviderStateMixin { late TabController tabController; HomeController() { tabController = TabController(length: Sites.supportSites.length, vsync: this); } StreamSubscription? streamSubscription; @override void onInit() { streamSubscription = EventBus.instance.listen( EventBus.kBottomNavigationBarClicked, (index) { if (index == 0) { refreshOrScrollTop(); } }, ); for (var site in Sites.supportSites) { Get.put(HomeListController(site), tag: site.id); } super.onInit(); } void refreshOrScrollTop() { var tabIndex = tabController.index; BasePageController controller; controller = Get.find(tag: Sites.supportSites[tabIndex].id); controller.scrollToTopOrRefresh(); } void toSearch() { Get.toNamed(RoutePath.kSearch); } @override void onClose() { streamSubscription?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/home/home_list_controller.dart ================================================ import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_core/simple_live_core.dart'; class HomeListController extends BasePageController { final Site site; HomeListController(this.site); @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.getRecommendRooms(page: page); return result.items; } } ================================================ FILE: simple_live_app/lib/modules/home/home_list_view.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/home/home_list_controller.dart'; import 'package:simple_live_app/widgets/keep_alive_wrapper.dart'; import 'package:simple_live_app/widgets/live_room_card.dart'; import 'package:simple_live_app/widgets/page_grid_view.dart'; class HomeListView extends StatelessWidget { final String tag; const HomeListView(this.tag, {Key? key}) : super(key: key); HomeListController get controller => Get.find(tag: tag); @override Widget build(BuildContext context) { var c = MediaQuery.of(context).size.width ~/ 200; if (c < 2) { c = 2; } return KeepAliveWrapper( child: PageGridView( pageController: controller, padding: AppStyle.edgeInsetsA12, firstRefresh: true, mainAxisSpacing: 12, crossAxisSpacing: 12, crossAxisCount: c, itemBuilder: (_, i) { var item = controller.list[i]; return LiveRoomCard(controller.site, item); }, ), ); } } ================================================ FILE: simple_live_app/lib/modules/home/home_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/home/home_controller.dart'; import 'package:simple_live_app/modules/home/home_list_view.dart'; class HomePage extends GetView { const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( titleSpacing: 8, title: TabBar( controller: controller.tabController, labelPadding: AppStyle.edgeInsetsH20, isScrollable: true, indicatorSize: TabBarIndicatorSize.label, tabAlignment: TabAlignment.center, tabs: Sites.supportSites .map( (e) => Tab( //text: e.name, child: Row( children: [ Image.asset( e.logo, width: 24, ), AppStyle.hGap8, Text(e.name), ], ), ), ) .toList(), ), actions: [ IconButton( onPressed: controller.toSearch, icon: const Icon(Icons.search), ) ], ), body: TabBarView( controller: controller.tabController, children: Sites.supportSites .map( (e) => HomeListView( e.id, ), ) .toList(), ), ); } } ================================================ FILE: simple_live_app/lib/modules/indexed/indexed_controller.dart ================================================ import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/category/category_controller.dart'; import 'package:simple_live_app/modules/category/category_page.dart'; import 'package:simple_live_app/modules/home/home_controller.dart'; import 'package:simple_live_app/modules/home/home_page.dart'; import 'package:simple_live_app/modules/follow_user/follow_user_controller.dart'; import 'package:simple_live_app/modules/follow_user/follow_user_page.dart'; import 'package:simple_live_app/modules/mine/mine_page.dart'; class IndexedController extends GetxController { RxList items = RxList([]); var index = 0.obs; RxList pages = RxList([ const SizedBox(), const SizedBox(), const SizedBox(), const SizedBox(), ]); void setIndex(int i) { if (pages[i] is SizedBox) { switch (items[i].index) { case 0: Get.put(HomeController()); pages[i] = const HomePage(); break; case 1: Get.put(FollowUserController()); pages[i] = const FollowUserPage(); break; case 2: Get.put(CategoryController()); pages[i] = const CategoryPage(); break; case 3: pages[i] = const MinePage(); break; default: } } else { if (index.value == i) { EventBus.instance .emit(EventBus.kBottomNavigationBarClicked, items[i].index); } } index.value = i; } @override void onInit() { Future.delayed(Duration.zero, showFirstRun); items.value = AppSettingsController.instance.homeSort .map((key) => Constant.allHomePages[key]!) .toList(); setIndex(0); super.onInit(); } void showFirstRun() async { var settingsController = Get.find(); if (settingsController.firstRun) { settingsController.setNoFirstRun(); await Utils.showStatement(); } } } ================================================ FILE: simple_live_app/lib/modules/indexed/indexed_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'indexed_controller.dart'; class IndexedPage extends GetView { const IndexedPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return OrientationBuilder( builder: (context, orientation) { return Scaffold( body: Row( children: [ Visibility( visible: orientation == Orientation.landscape, child: Obx( () => NavigationRail( selectedIndex: controller.index.value, onDestinationSelected: controller.setIndex, labelType: NavigationRailLabelType.none, destinations: controller.items .map( (item) => NavigationRailDestination( icon: Icon(item.iconData), label: Text(item.title), padding: AppStyle.edgeInsetsV8, ), ) .toList(), ), ), ), Expanded( child: Obx( () => Container( decoration: BoxDecoration( border: Border( left: orientation == Orientation.landscape ? BorderSide( color: Colors.grey.withAlpha(50), width: 1, ) : BorderSide.none, ), ), child: IndexedStack( index: controller.index.value, children: controller.pages, ), ), ), ), ], ), bottomNavigationBar: Visibility( visible: orientation == Orientation.portrait, child: Obx( () => NavigationBar( selectedIndex: controller.index.value, onDestinationSelected: controller.setIndex, height: 56, labelBehavior: NavigationDestinationLabelBehavior.alwaysHide, destinations: controller.items .map( (item) => NavigationDestination( icon: Icon(item.iconData), label: item.title, ), ) .toList(), ), ), ), ); }, ); } } ================================================ FILE: simple_live_app/lib/modules/live_room/live_room_controller.dart ================================================ import 'dart:async'; import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:media_kit/media_kit.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:share_plus/share_plus.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:simple_live_app/modules/live_room/player/player_controller.dart'; import 'package:simple_live_app/modules/settings/danmu_settings_page.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:simple_live_app/services/follow_service.dart'; import 'package:simple_live_app/widgets/desktop_refresh_button.dart'; import 'package:simple_live_app/widgets/follow_user_item.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; class LiveRoomController extends PlayerController with WidgetsBindingObserver { final Site pSite; final String pRoomId; late LiveDanmaku liveDanmaku; LiveRoomController({ required this.pSite, required this.pRoomId, }) { rxSite = pSite.obs; rxRoomId = pRoomId.obs; liveDanmaku = site.liveSite.getDanmaku(); // 抖音应该默认是竖屏的 if (site.id == "douyin") { isVertical.value = true; } } late Rx rxSite; Site get site => rxSite.value; late Rx rxRoomId; String get roomId => rxRoomId.value; Rx detail = Rx(null); var online = 0.obs; var followed = false.obs; var liveStatus = false.obs; RxList superChats = RxList(); /// 滚动控制 final ScrollController scrollController = ScrollController(); /// 聊天信息 RxList messages = RxList(); /// 清晰度数据 RxList qualites = RxList(); /// 当前清晰度 var currentQuality = -1; var currentQualityInfo = "".obs; /// 线路数据 RxList playUrls = RxList(); Map? playHeaders; /// 当前线路 var currentLineIndex = -1; var currentLineInfo = "".obs; /// 退出倒计时 var countdown = 60.obs; Timer? autoExitTimer; /// 设置的自动关闭时间(分钟) var autoExitMinutes = 60.obs; ///是否延迟自动关闭 var delayAutoExit = false.obs; /// 是否启用自动关闭 var autoExitEnable = false.obs; /// 是否禁用自动滚动聊天栏 /// - 当用户向上滚动聊天栏时,不再自动滚动 var disableAutoScroll = false.obs; /// 是否处于后台 var isBackground = false; /// 直播间加载失败 var loadError = false.obs; Error? error; // 开播时长状态变量 var liveDuration = "00:00:00".obs; Timer? _liveDurationTimer; @override void onInit() { WidgetsBinding.instance.addObserver(this); if (FollowService.instance.followList.isEmpty) { FollowService.instance.loadData(); } initAutoExit(); showDanmakuState.value = AppSettingsController.instance.danmuEnable.value; followed.value = DBService.instance.getFollowExist("${site.id}_$roomId"); loadData(); scrollController.addListener(scrollListener); super.onInit(); } void scrollListener() { if (scrollController.position.userScrollDirection == ScrollDirection.forward) { disableAutoScroll.value = true; } } /// 初始化自动关闭倒计时 void initAutoExit() { if (AppSettingsController.instance.autoExitEnable.value) { autoExitEnable.value = true; autoExitMinutes.value = AppSettingsController.instance.autoExitDuration.value; setAutoExit(); } else { autoExitMinutes.value = AppSettingsController.instance.roomAutoExitDuration.value; } } void setAutoExit() { if (!autoExitEnable.value) { autoExitTimer?.cancel(); return; } autoExitTimer?.cancel(); countdown.value = autoExitMinutes.value * 60; autoExitTimer = Timer.periodic(const Duration(seconds: 1), (timer) async { countdown.value -= 1; if (countdown.value <= 0) { timer = Timer(const Duration(seconds: 10), () async { await WakelockPlus.disable(); exit(0); }); autoExitTimer?.cancel(); var delay = await Utils.showAlertDialog("定时关闭已到时,是否延迟关闭?", title: "延迟关闭", confirm: "延迟", cancel: "关闭", selectable: true); if (delay) { timer.cancel(); delayAutoExit.value = true; showAutoExitSheet(); setAutoExit(); } else { delayAutoExit.value = false; await WakelockPlus.disable(); exit(0); } } }); } // 弹窗逻辑 void refreshRoom() { //messages.clear(); superChats.clear(); liveDanmaku.stop(); loadData(); } /// 聊天栏始终滚动到底部 void chatScrollToBottom() { if (scrollController.hasClients) { // 如果手动上拉过,就不自动滚动到底部 if (disableAutoScroll.value) { return; } scrollController.jumpTo(scrollController.position.maxScrollExtent); } } /// 初始化弹幕接收事件 void initDanmau() { liveDanmaku.onMessage = onWSMessage; liveDanmaku.onClose = onWSClose; liveDanmaku.onReady = onWSReady; } /// 接收到WebSocket信息 void onWSMessage(LiveMessage msg) { if (msg.type == LiveMessageType.chat) { if (messages.length > 200 && !disableAutoScroll.value) { messages.removeAt(0); } // 关键词屏蔽检查 for (var keyword in AppSettingsController.instance.shieldList) { Pattern? pattern; if (Utils.isRegexFormat(keyword)) { String removedSlash = Utils.removeRegexFormat(keyword); try { pattern = RegExp(removedSlash); } catch (e) { // should avoid this during add keyword Log.d("关键词:$keyword 正则格式错误"); } } else { pattern = keyword; } if (pattern != null && msg.message.contains(pattern)) { Log.d("关键词:$keyword\n已屏蔽消息内容:${msg.message}"); return; } } messages.add(msg); WidgetsBinding.instance.addPostFrameCallback( (_) => chatScrollToBottom(), ); if (!liveStatus.value || isBackground) { return; } addDanmaku([ DanmakuContentItem( msg.message, color: Color.fromARGB( 255, msg.color.r, msg.color.g, msg.color.b, ), ), ]); } else if (msg.type == LiveMessageType.online) { online.value = msg.data; } else if (msg.type == LiveMessageType.superChat) { superChats.add(msg.data); } } /// 添加一条系统消息 void addSysMsg(String msg) { messages.add( LiveMessage( type: LiveMessageType.chat, userName: "LiveSysMessage", message: msg, color: LiveMessageColor.white, ), ); } /// 接收到WebSocket关闭信息 void onWSClose(String msg) { addSysMsg(msg); } /// WebSocket准备就绪 void onWSReady() { addSysMsg("弹幕服务器连接正常"); } /// 加载直播间信息 void loadData() async { try { SmartDialog.showLoading(msg: ""); loadError.value = false; error = null; update(); addSysMsg("正在读取直播间信息"); detail.value = await site.liveSite.getRoomDetail(roomId: roomId); if (site.id == Constant.kDouyin) { // 1.6.0之前收藏的WebRid // 1.6.0收藏的RoomID // 1.6.0之后改回WebRid if (detail.value!.roomId != roomId) { var oldId = roomId; rxRoomId.value = detail.value!.roomId; if (followed.value) { // 更新关注列表 DBService.instance.deleteFollow("${site.id}_$oldId"); DBService.instance.addFollow( FollowUser( id: "${site.id}_$roomId", roomId: roomId, siteId: site.id, userName: detail.value!.userName, face: detail.value!.userAvatar, addTime: DateTime.now(), ), ); } else { followed.value = DBService.instance.getFollowExist("${site.id}_$roomId"); } } } getSuperChatMessage(); addHistory(); // 确认房间关注状态 followed.value = DBService.instance.getFollowExist("${site.id}_$roomId"); online.value = detail.value!.online; liveStatus.value = detail.value!.status || detail.value!.isRecord; if (liveStatus.value) { getPlayQualites(); } if (detail.value!.isRecord) { addSysMsg("当前主播未开播,正在轮播录像"); } addSysMsg("开始连接弹幕服务器"); initDanmau(); liveDanmaku.start(detail.value?.danmakuData); startLiveDurationTimer(); // 启动开播时长定时器 } catch (e) { Log.logPrint(e); //SmartDialog.showToast(e.toString()); loadError.value = true; error = e as Error; } finally { SmartDialog.dismiss(status: SmartStatus.loading); } } /// 初始化播放器 void getPlayQualites() async { qualites.clear(); currentQuality = -1; try { var playQualites = await site.liveSite.getPlayQualites(detail: detail.value!); if (playQualites.isEmpty) { SmartDialog.showToast("无法读取播放清晰度"); return; } qualites.value = playQualites; var qualityLevel = await getQualityLevel(); if (qualityLevel == 2) { //最高 currentQuality = 0; } else if (qualityLevel == 0) { //最低 currentQuality = playQualites.length - 1; } else { //中间值 int middle = (playQualites.length / 2).floor(); currentQuality = middle; } getPlayUrl(); } catch (e) { Log.logPrint(e); SmartDialog.showToast("无法读取播放清晰度"); } } Future getQualityLevel() async { var qualityLevel = AppSettingsController.instance.qualityLevel.value; try { var connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult.first == ConnectivityResult.mobile) { qualityLevel = AppSettingsController.instance.qualityLevelCellular.value; } } catch (e) { Log.logPrint(e); } return qualityLevel; } void getPlayUrl() async { playUrls.clear(); currentQualityInfo.value = qualites[currentQuality].quality; currentLineInfo.value = ""; currentLineIndex = -1; var playUrl = await site.liveSite .getPlayUrls(detail: detail.value!, quality: qualites[currentQuality]); if (playUrl.urls.isEmpty) { SmartDialog.showToast("无法读取播放地址"); return; } playUrls.value = playUrl.urls; playHeaders = playUrl.headers; currentLineIndex = 0; currentLineInfo.value = "线路${currentLineIndex + 1}"; //重置错误次数 mediaErrorRetryCount = 0; initPlaylist(); } void changePlayLine(int index) { currentLineIndex = index; //重置错误次数 mediaErrorRetryCount = 0; setPlayer(); } void initPlaylist() async { currentLineInfo.value = "线路${currentLineIndex + 1}"; errorMsg.value = ""; final mediaList = playUrls.map((url) { var finalUrl = url; if (AppSettingsController.instance.playerForceHttps.value) { finalUrl = finalUrl.replaceAll("http://", "https://"); } return Media(finalUrl, httpHeaders: playHeaders); }).toList(); // 初始化播放器并设置 ao 参数 await initializePlayer(); await player.open(Playlist(mediaList)); } void setPlayer() async { currentLineInfo.value = "线路${currentLineIndex + 1}"; errorMsg.value = ""; await player.jump(currentLineIndex); } @override void mediaEnd() async { super.mediaEnd(); if (mediaErrorRetryCount < 2) { Log.d("播放结束,尝试第${mediaErrorRetryCount + 1}次刷新"); if (mediaErrorRetryCount == 1) { //延迟一秒再刷新 await Future.delayed(const Duration(seconds: 1)); } mediaErrorRetryCount += 1; //刷新一次 setPlayer(); return; } Log.d("播放结束"); // 遍历线路,如果全部链接都断开就是直播结束了 if (playUrls.length - 1 == currentLineIndex) { liveStatus.value = false; } else { changePlayLine(currentLineIndex + 1); //setPlayer(); } } int mediaErrorRetryCount = 0; @override void mediaError(String error) async { super.mediaEnd(); if (mediaErrorRetryCount < 2) { Log.d("播放失败,尝试第${mediaErrorRetryCount + 1}次刷新"); if (mediaErrorRetryCount == 1) { //延迟一秒再刷新 await Future.delayed(const Duration(seconds: 1)); } mediaErrorRetryCount += 1; //刷新一次 setPlayer(); return; } if (playUrls.length - 1 == currentLineIndex) { errorMsg.value = "播放失败"; SmartDialog.showToast("播放失败:$error"); } else { //currentLineIndex += 1; //setPlayer(); changePlayLine(currentLineIndex + 1); } } /// 读取SC void getSuperChatMessage() async { try { var sc = await site.liveSite.getSuperChatMessage(roomId: detail.value!.roomId); superChats.addAll(sc); } catch (e) { Log.logPrint(e); addSysMsg("SC读取失败"); } } /// 移除掉已到期的SC void removeSuperChats() async { var now = DateTime.now().millisecondsSinceEpoch; superChats.value = superChats .where((x) => x.endTime.millisecondsSinceEpoch > now) .toList(); } /// 添加历史记录 void addHistory() { if (detail.value == null) { return; } var id = "${site.id}_$roomId"; var history = DBService.instance.getHistory(id); if (history != null) { history.updateTime = DateTime.now(); } history ??= History( id: id, roomId: roomId, siteId: site.id, userName: detail.value?.userName ?? "", face: detail.value?.userAvatar ?? "", updateTime: DateTime.now(), ); DBService.instance.addOrUpdateHistory(history); } /// 关注用户 void followUser() { if (detail.value == null) { return; } var id = "${site.id}_$roomId"; DBService.instance.addFollow( FollowUser( id: id, roomId: roomId, siteId: site.id, userName: detail.value?.userName ?? "", face: detail.value?.userAvatar ?? "", addTime: DateTime.now(), ), ); followed.value = true; EventBus.instance.emit(Constant.kUpdateFollow, id); } /// 取消关注用户 void removeFollowUser() async { if (detail.value == null) { return; } if (!await Utils.showAlertDialog("确定要取消关注该用户吗?", title: "取消关注")) { return; } var id = "${site.id}_$roomId"; DBService.instance.deleteFollow(id); followed.value = false; EventBus.instance.emit(Constant.kUpdateFollow, id); } void share() { if (detail.value == null) { return; } SharePlus.instance.share(ShareParams(uri: Uri.parse(detail.value!.url))); } void copyUrl() { if (detail.value == null) { return; } Utils.copyToClipboard(detail.value!.url); SmartDialog.showToast("已复制直播间链接"); } /// 复制新生成的直播流 void copyPlayUrl() async { // 未开播不复制 if (!liveStatus.value) { return; } var playUrl = await site.liveSite .getPlayUrls(detail: detail.value!, quality: qualites[currentQuality]); if (playUrl.urls.isEmpty) { SmartDialog.showToast("无法读取播放地址"); return; } Utils.copyToClipboard(playUrl.urls.first); SmartDialog.showToast("已复制播放直链"); } /// 底部打开播放器设置 void showDanmuSettingsSheet() { Utils.showBottomSheet( title: "弹幕设置", child: ListView( padding: AppStyle.edgeInsetsA12, children: [ DanmuSettingsView( danmakuController: danmakuController, onTapDanmuShield: () { Get.back(); showDanmuShield(); }, ), ], ), ); } void showVolumeSlider(BuildContext targetContext) { SmartDialog.showAttach( targetContext: targetContext, alignment: Alignment.topCenter, displayTime: const Duration(seconds: 3), maskColor: const Color(0x00000000), builder: (context) { return Container( decoration: BoxDecoration( borderRadius: AppStyle.radius12, color: Theme.of(context).cardColor, ), padding: AppStyle.edgeInsetsA4, child: Obx( () => SizedBox( width: 200, child: Slider( min: 0, max: 100, value: AppSettingsController.instance.playerVolume.value, onChanged: (newValue) { player.setVolume(newValue); AppSettingsController.instance.setPlayerVolume(newValue); }, ), ), ), ); }, ); } void showQualitySheet() { Utils.showBottomSheet( title: "切换清晰度", child: RadioGroup( groupValue: currentQuality, onChanged: (e) { Get.back(); currentQuality = e ?? 0; getPlayUrl(); }, child: ListView.builder( itemCount: qualites.length, itemBuilder: (_, i) { var item = qualites[i]; return RadioListTile( value: i, title: Text(item.quality), ); }, ), ), ); } void showPlayUrlsSheet() { Utils.showBottomSheet( title: "切换线路", child: RadioGroup( groupValue: currentLineIndex, onChanged: (e) { Get.back(); //currentLineIndex = i; //setPlayer(); changePlayLine(e ?? 0); }, child: ListView.builder( itemCount: playUrls.length, itemBuilder: (_, i) { return RadioListTile( value: i, title: Text("线路${i + 1}"), secondary: Text( playUrls[i].contains(".flv") ? "FLV" : "HLS", ), ); }, ), ), ); } void showPlayerSettingsSheet() { Utils.showBottomSheet( title: "画面尺寸", child: Obx( () => RadioGroup( groupValue: AppSettingsController.instance.scaleMode.value, onChanged: (e) { AppSettingsController.instance.setScaleMode(e ?? 0); updateScaleMode(); }, child: ListView( padding: AppStyle.edgeInsetsV12, children: const [ RadioListTile( value: 0, title: Text("适应"), visualDensity: VisualDensity.compact, ), RadioListTile( value: 1, title: Text("拉伸"), visualDensity: VisualDensity.compact, ), RadioListTile( value: 2, title: Text("铺满"), visualDensity: VisualDensity.compact, ), RadioListTile( value: 3, title: Text("16:9"), visualDensity: VisualDensity.compact, ), RadioListTile( value: 4, title: Text("4:3"), visualDensity: VisualDensity.compact, ), ], ), ), ), ); } void showDanmuShield() { TextEditingController keywordController = TextEditingController(); void addKeyword() { if (keywordController.text.isEmpty) { SmartDialog.showToast("请输入关键词"); return; } AppSettingsController.instance .addShieldList(keywordController.text.trim()); keywordController.text = ""; } Utils.showBottomSheet( title: "关键词屏蔽", child: ListView( padding: AppStyle.edgeInsetsA12, children: [ TextField( controller: keywordController, decoration: InputDecoration( contentPadding: AppStyle.edgeInsetsH12, border: const OutlineInputBorder(), hintText: "请输入关键词", suffixIcon: TextButton.icon( onPressed: addKeyword, icon: const Icon(Icons.add), label: const Text("添加"), ), ), onSubmitted: (e) { addKeyword(); }, ), AppStyle.vGap12, Obx( () => Text( "已添加${AppSettingsController.instance.shieldList.length}个关键词(点击移除)", style: Get.textTheme.titleSmall, ), ), AppStyle.vGap12, Obx( () => Wrap( runSpacing: 12, spacing: 12, children: AppSettingsController.instance.shieldList .map( (item) => InkWell( borderRadius: AppStyle.radius24, onTap: () { AppSettingsController.instance.removeShieldList(item); }, child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: AppStyle.radius24, ), padding: AppStyle.edgeInsetsH12.copyWith( top: 4, bottom: 4, ), child: Text( item, style: Get.textTheme.bodyMedium, ), ), ), ) .toList(), ), ), ], ), ); } void showFollowUserSheet() { Utils.showBottomSheet( title: "关注列表", child: Obx( () => Stack( children: [ RefreshIndicator( onRefresh: FollowService.instance.loadData, child: ListView.builder( itemCount: FollowService.instance.liveList.length, itemBuilder: (_, i) { var item = FollowService.instance.liveList[i]; return Obx( () => FollowUserItem( item: item, playing: rxSite.value.id == item.siteId && rxRoomId.value == item.roomId, onTap: () { Get.back(); resetRoom( Sites.allSites[item.siteId]!, item.roomId, ); }, ), ); }, ), ), if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) Positioned( right: 12, bottom: 12, child: Obx( () => DesktopRefreshButton( refreshing: FollowService.instance.updating.value, onPressed: FollowService.instance.loadData, ), ), ), ], ), ), ); } void showAutoExitSheet() { if (AppSettingsController.instance.autoExitEnable.value && !delayAutoExit.value) { SmartDialog.showToast("已设置了全局定时关闭"); return; } Utils.showBottomSheet( title: "定时关闭", child: ListView( children: [ Obx( () => SwitchListTile( title: Text( "启用定时关闭", style: Get.textTheme.titleMedium, ), value: autoExitEnable.value, onChanged: (e) { autoExitEnable.value = e; setAutoExit(); //controller.setAutoExitEnable(e); }, ), ), Obx( () => ListTile( enabled: autoExitEnable.value, title: Text( "自动关闭时间:${autoExitMinutes.value ~/ 60}小时${autoExitMinutes.value % 60}分钟", style: Get.textTheme.titleMedium, ), trailing: const Icon(Icons.chevron_right), onTap: () async { var value = await showTimePicker( context: Get.context!, initialTime: TimeOfDay( hour: autoExitMinutes.value ~/ 60, minute: autoExitMinutes.value % 60, ), initialEntryMode: TimePickerEntryMode.inputOnly, builder: (_, child) { return MediaQuery( data: Get.mediaQuery.copyWith( alwaysUse24HourFormat: true, ), child: child!, ); }, ); if (value == null || (value.hour == 0 && value.minute == 0)) { return; } var duration = Duration(hours: value.hour, minutes: value.minute); autoExitMinutes.value = duration.inMinutes; AppSettingsController.instance .setRoomAutoExitDuration(autoExitMinutes.value); //setAutoExitDuration(duration.inMinutes); setAutoExit(); }, ), ), ], ), ); } void openNaviteAPP() async { var naviteUrl = ""; var webUrl = ""; if (site.id == Constant.kBiliBili) { naviteUrl = "bilibili://live/${detail.value?.roomId}"; webUrl = "https://live.bilibili.com/${detail.value?.roomId}"; } else if (site.id == Constant.kDouyin) { var args = detail.value?.danmakuData as DouyinDanmakuArgs; naviteUrl = "snssdk1128://webcast_room?room_id=${args.roomId}"; webUrl = "https://live.douyin.com/${args.webRid}"; } else if (site.id == Constant.kHuya) { var args = detail.value?.danmakuData as HuyaDanmakuArgs; naviteUrl = "yykiwi://homepage/index.html?banneraction=https%3A%2F%2Fdiy-front.cdn.huya.com%2Fzt%2Ffrontpage%2Fcc%2Fupdate.html%3Fhyaction%3Dlive%26channelid%3D${args.subSid}%26subid%3D${args.subSid}%26liveuid%3D${args.subSid}%26screentype%3D1%26sourcetype%3D0%26fromapp%3Dhuya_wap%252Fclick%252Fopen_app_guide%26&fromapp=huya_wap/click/open_app_guide"; webUrl = "https://www.huya.com/${detail.value?.roomId}"; } else if (site.id == Constant.kDouyu) { naviteUrl = "douyulink://?type=90001&schemeUrl=douyuapp%3A%2F%2Froom%3FliveType%3D0%26rid%3D${detail.value?.roomId}"; webUrl = "https://www.douyu.com/${detail.value?.roomId}"; } try { await launchUrlString(naviteUrl, mode: LaunchMode.externalApplication); } catch (e) { Log.logPrint(e); SmartDialog.showToast("无法打开APP,将使用浏览器打开"); await launchUrlString(webUrl, mode: LaunchMode.externalApplication); } } void resetRoom(Site site, String roomId) async { if (this.site == site && this.roomId == roomId) { return; } rxSite.value = site; rxRoomId.value = roomId; // 清除全部消息 liveDanmaku.stop(); messages.clear(); superChats.clear(); danmakuController?.clear(); // 重新设置LiveDanmaku liveDanmaku = site.liveSite.getDanmaku(); // 停止播放 await player.stop(); // 刷新信息 loadData(); } void copyErrorDetail() { Utils.copyToClipboard('''直播平台:${rxSite.value.name} 房间号:${rxRoomId.value} 错误信息: ${error?.toString()} ---------------- ${error?.stackTrace}'''); SmartDialog.showToast("已复制错误信息"); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.paused) { Log.d("进入后台"); //进入后台,关闭弹幕 danmakuController?.clear(); isBackground = true; } else //返回前台 if (state == AppLifecycleState.resumed) { Log.d("返回前台"); isBackground = false; } } // 用于启动开播时长计算和更新的函数 void startLiveDurationTimer() { // 如果不是直播状态或者 showTime 为空,则不启动定时器 if (!(detail.value?.status ?? false) || detail.value?.showTime == null) { liveDuration.value = "00:00:00"; // 未开播时显示 00:00:00 _liveDurationTimer?.cancel(); return; } try { int startTimeStamp = int.parse(detail.value!.showTime!); // 取消之前的定时器 _liveDurationTimer?.cancel(); // 创建新的定时器,每秒更新一次 _liveDurationTimer = Timer.periodic(const Duration(seconds: 1), (timer) { int currentTimeStamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; int durationInSeconds = currentTimeStamp - startTimeStamp; int hours = durationInSeconds ~/ 3600; int minutes = (durationInSeconds % 3600) ~/ 60; int seconds = durationInSeconds % 60; String formattedDuration = '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; liveDuration.value = formattedDuration; }); } catch (e) { liveDuration.value = "--:--:--"; // 错误时显示 --:--:-- } } @override void onClose() { WidgetsBinding.instance.removeObserver(this); scrollController.removeListener(scrollListener); autoExitTimer?.cancel(); liveDanmaku.stop(); danmakuController = null; _liveDurationTimer?.cancel(); // 页面关闭时取消定时器 super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/live_room/live_room_page.dart ================================================ import 'dart:io'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:lottie/lottie.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/live_room/live_room_controller.dart'; import 'package:simple_live_app/modules/live_room/player/player_controls.dart'; import 'package:simple_live_app/services/follow_service.dart'; import 'package:simple_live_app/widgets/desktop_refresh_button.dart'; import 'package:simple_live_app/widgets/follow_user_item.dart'; import 'package:simple_live_app/widgets/keep_alive_wrapper.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'package:simple_live_app/widgets/settings/settings_action.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_number.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; import 'package:simple_live_app/widgets/superchat_card.dart'; import 'package:simple_live_core/simple_live_core.dart'; class LiveRoomPage extends GetView { const LiveRoomPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final page = Obx( () { if (controller.loadError.value) { return Scaffold( appBar: AppBar( title: const Text("直播间加载失败"), ), body: Padding( padding: AppStyle.edgeInsetsA12, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.center, children: [ LottieBuilder.asset( 'assets/lotties/error.json', height: 140, repeat: false, ), const Text( "直播间加载失败", textAlign: TextAlign.center, ), AppStyle.vGap4, Text( controller.error?.toString() ?? "未知错误", textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12, color: Colors.grey), ), AppStyle.vGap4, Text( "${controller.rxSite.value.id} - ${controller.rxRoomId.value}", textAlign: TextAlign.center, style: const TextStyle(fontSize: 12, color: Colors.grey), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton.icon( onPressed: controller.copyErrorDetail, icon: const Icon(Remix.file_copy_line), label: const Text("复制信息"), ), TextButton.icon( onPressed: controller.refreshRoom, icon: const Icon(Remix.refresh_line), label: const Text("刷新"), ), ], ) ], ), ), ); } if (controller.fullScreenState.value) { return PopScope( canPop: false, onPopInvokedWithResult: (e, r) { controller.exitFull(); }, child: Scaffold( body: buildMediaPlayer(), ), ); } else { return buildPageUI(); } }, ); if (!Platform.isAndroid) { return page; } return PiPSwitcher( floating: controller.pip, childWhenDisabled: page, childWhenEnabled: buildMediaPlayer(), ); } Widget buildPageUI() { return OrientationBuilder( builder: (context, orientation) { return Scaffold( appBar: AppBar( title: Obx( () => Text(controller.detail.value?.title ?? "直播间"), ), actions: buildAppbarActions(context), ), body: orientation == Orientation.portrait ? buildPhoneUI(context) : buildTabletUI(context), ); }, ); } Widget buildPhoneUI(BuildContext context) { return Column( children: [ AspectRatio( aspectRatio: 16 / 9, child: buildMediaPlayer(), ), buildUserProfile(context), buildMessageArea(), buildBottomActions(context), ], ); } Widget buildTabletUI(BuildContext context) { return Column( children: [ Expanded( child: Row( children: [ Expanded( child: buildMediaPlayer(), ), SizedBox( width: 300, child: Column( children: [ buildUserProfile(context), buildMessageArea(), ], ), ), ], ), ), Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, border: Border( top: BorderSide( color: Colors.grey.withAlpha(25), ), ), ), padding: AppStyle.edgeInsetsV4.copyWith( bottom: AppStyle.bottomBarHeight + 4, ), child: Row( children: [ TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.refreshRoom, icon: const Icon(Remix.refresh_line), label: const Text("刷新"), ), AppStyle.hGap4, Obx( () => controller.followed.value ? TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.removeFollowUser, icon: const Icon(Remix.heart_fill), label: const Text("取消关注"), ) : TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.followUser, icon: const Icon(Remix.heart_line), label: const Text("关注"), ), ), const Expanded(child: Center()), TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.share, icon: const Icon(Remix.share_line), label: const Text("分享"), ), TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.copyUrl, icon: const Icon(Remix.file_copy_line), label: const Text("复制链接"), ), TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.copyPlayUrl, icon: const Icon(Remix.file_copy_line), label: const Text("复制播放直链"), ), ], ), ), ], ); } Widget buildMediaPlayer() { var boxFit = BoxFit.contain; double? aspectRatio; if (AppSettingsController.instance.scaleMode.value == 0) { boxFit = BoxFit.contain; } else if (AppSettingsController.instance.scaleMode.value == 1) { boxFit = BoxFit.fill; } else if (AppSettingsController.instance.scaleMode.value == 2) { boxFit = BoxFit.cover; } else if (AppSettingsController.instance.scaleMode.value == 3) { boxFit = BoxFit.contain; aspectRatio = 16 / 9; } else if (AppSettingsController.instance.scaleMode.value == 4) { boxFit = BoxFit.contain; aspectRatio = 4 / 3; } return Stack( children: [ Video( key: controller.globalPlayerKey, controller: controller.videoController, pauseUponEnteringBackgroundMode: AppSettingsController.instance.playerAutoPause.value, resumeUponEnteringForegroundMode: AppSettingsController.instance.playerAutoPause.value, controls: (state) { return playerControls(state, controller); }, aspectRatio: aspectRatio, fit: boxFit, // 自己实现 wakelock: false, ), Obx( () => Visibility( visible: !controller.liveStatus.value, child: const Center( child: Text( "未开播", style: TextStyle(fontSize: 16, color: Colors.white), ), ), ), ), ], ); } Widget buildUserProfile(BuildContext context) { return Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, border: Border( top: BorderSide( color: Colors.grey.withAlpha(25), ), bottom: BorderSide( color: Colors.grey.withAlpha(25), ), ), ), padding: AppStyle.edgeInsetsA8.copyWith( left: 12, right: 12, ), child: Obx( () => Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey.withAlpha(50)), borderRadius: AppStyle.radius24, ), child: NetImage( controller.detail.value?.userAvatar ?? "", width: 48, height: 48, borderRadius: 24, ), ), AppStyle.hGap12, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( controller.detail.value?.userName ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, ), AppStyle.vGap4, Row( children: [ Image.asset( controller.site.logo, width: 20, ), AppStyle.hGap4, Text( controller.site.name, style: const TextStyle( fontSize: 12, color: Colors.grey, ), ), ], ), ], ), ), AppStyle.hGap12, Row( mainAxisSize: MainAxisSize.min, children: [ const Icon( Remix.fire_fill, size: 20, color: Colors.orange, ), AppStyle.hGap4, Text( Utils.onlineToString( controller.detail.value?.online ?? 0, ), style: const TextStyle(fontSize: 14), ), ], ), ], ), ), ); } Widget buildBottomActions(BuildContext context) { return Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, border: Border( top: BorderSide( color: Colors.grey.withAlpha(25), ), ), ), padding: EdgeInsets.only(bottom: AppStyle.bottomBarHeight), child: Row( children: [ Expanded( child: Obx( () => controller.followed.value ? TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.removeFollowUser, icon: const Icon(Remix.heart_fill), label: const Text("取消关注"), ) : TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.followUser, icon: const Icon(Remix.heart_line), label: const Text("关注"), ), ), ), Expanded( child: TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.refreshRoom, icon: const Icon(Remix.refresh_line), label: const Text("刷新"), ), ), Expanded( child: TextButton.icon( style: TextButton.styleFrom( textStyle: const TextStyle(fontSize: 14), ), onPressed: controller.share, icon: const Icon(Remix.share_line), label: const Text("分享"), ), ), ], ), ); } Widget buildMessageArea() { return Expanded( child: DefaultTabController( length: controller.site.id == Constant.kBiliBili ? 4 : 3, child: Column( children: [ TabBar( indicatorSize: TabBarIndicatorSize.tab, labelPadding: EdgeInsets.zero, indicatorWeight: 1.0, tabs: [ const Tab( text: "聊天", ), if (controller.site.id == Constant.kBiliBili) Tab( child: Obx( () => Text( controller.superChats.isNotEmpty ? "SC(${controller.superChats.length})" : "SC", ), ), ), const Tab( text: "关注", ), const Tab( text: "设置", ), ], ), Expanded( child: TabBarView( children: [ Obx( () => Stack( children: [ ListView.separated( controller: controller.scrollController, separatorBuilder: (_, i) => Obx( () => SizedBox( // *2与原来的EdgeInsets.symmetric(vertical: )做兼容 height: AppSettingsController .instance.chatTextGap.value * 2, ), ), padding: AppStyle.edgeInsetsA12, itemCount: controller.messages.length, itemBuilder: (_, i) { var item = controller.messages[i]; return buildMessageItem(item); }, ), Visibility( visible: controller.disableAutoScroll.value, child: Positioned( right: 12, bottom: 12, child: ElevatedButton.icon( onPressed: () { controller.disableAutoScroll.value = false; controller.chatScrollToBottom(); }, icon: const Icon(Icons.expand_more), label: const Text("最新"), ), ), ), ], ), ), if (controller.site.id == Constant.kBiliBili) buildSuperChats(), buildFollowList(), buildSettings(), ], ), ), ], ), ), ); } Widget buildMessageItem(LiveMessage message) { if (message.userName == "LiveSysMessage") { return Obx( () => Text( message.message, style: TextStyle( color: Colors.grey, fontSize: AppSettingsController.instance.chatTextSize.value, ), ), ); } return Obx( () => AppSettingsController.instance.chatBubbleStyle.value ? Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Flexible( child: Container( decoration: BoxDecoration( color: Colors.blueGrey.withAlpha(25), //borderRadius: AppStyle.radius8, borderRadius: const BorderRadius.only( topRight: Radius.circular(12), bottomLeft: Radius.circular(12), bottomRight: Radius.circular(12), ), ), padding: AppStyle.edgeInsetsA4.copyWith(left: 12, right: 12), child: Text.rich( TextSpan( text: "${message.userName}:", style: TextStyle( color: Colors.grey, fontSize: AppSettingsController.instance.chatTextSize.value, ), children: [ TextSpan( text: message.message, style: TextStyle( color: Get.isDarkMode ? Colors.white : AppColors.black333, ), ) ], ), ), ), ), ], ) : Text.rich( TextSpan( text: "${message.userName}:", style: TextStyle( color: Colors.grey, fontSize: AppSettingsController.instance.chatTextSize.value, ), children: [ TextSpan( text: message.message, style: TextStyle( color: Get.isDarkMode ? Colors.white : AppColors.black333, ), ) ], ), ), ); } Widget buildSuperChats() { return KeepAliveWrapper( child: Obx( () => ListView.separated( padding: AppStyle.edgeInsetsA12, itemCount: controller.superChats.length, separatorBuilder: (_, i) => AppStyle.vGap12, itemBuilder: (_, i) { var item = controller.superChats[i]; return SuperChatCard( item, onExpire: () { controller.removeSuperChats(); }, ); }, ), ), ); } Widget buildSettings() { return ListView( padding: AppStyle.edgeInsetsA12, children: [ Obx( () => Visibility( visible: controller.autoExitEnable.value, child: ListTile( leading: const Icon(Icons.timer_outlined), visualDensity: VisualDensity.compact, title: Text("${parseDuration(controller.countdown.value)}后自动关闭"), ), ), ), Padding( padding: AppStyle.edgeInsetsA12, child: Text( "聊天区", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ Obx( () => SettingsNumber( title: "文字大小", value: AppSettingsController.instance.chatTextSize.value.toInt(), min: 8, max: 36, onChanged: (e) { AppSettingsController.instance .setChatTextSize(e.toDouble()); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "上下间隔", value: AppSettingsController.instance.chatTextGap.value.toInt(), min: 0, max: 12, onChanged: (e) { AppSettingsController.instance.setChatTextGap(e.toDouble()); }, ), ), AppStyle.divider, Obx( () => SettingsSwitch( title: "气泡样式", value: AppSettingsController.instance.chatBubbleStyle.value, onChanged: (e) { AppSettingsController.instance.setChatBubbleStyle(e); }, ), ), AppStyle.divider, Obx( () => SettingsSwitch( title: "播放器中显示SC", value: AppSettingsController.instance.playershowSuperChat.value, onChanged: (e) { AppSettingsController.instance.setPlayerShowSuperChat(e); }, ), ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12, child: Text( "更多设置", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ SettingsAction( title: "关键词屏蔽", onTap: controller.showDanmuShield, ), AppStyle.divider, SettingsAction( title: "弹幕设置", onTap: controller.showDanmuSettingsSheet, ), AppStyle.divider, SettingsAction( title: "定时关闭", onTap: controller.showAutoExitSheet, ), AppStyle.divider, SettingsAction( title: "画面尺寸", onTap: controller.showPlayerSettingsSheet, ), ], ), ), ], ); } Widget buildFollowList() { return Obx( () => Stack( children: [ RefreshIndicator( onRefresh: FollowService.instance.loadData, child: ListView.builder( itemCount: FollowService.instance.liveList.length, itemBuilder: (_, i) { var item = FollowService.instance.liveList[i]; return Obx( () => FollowUserItem( item: item, playing: controller.rxSite.value.id == item.siteId && controller.rxRoomId.value == item.roomId, onTap: () { controller.resetRoom( Sites.allSites[item.siteId]!, item.roomId, ); }, ), ); }, ), ), if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) Positioned( right: 12, bottom: 12, child: Obx( () => DesktopRefreshButton( refreshing: FollowService.instance.updating.value, onPressed: FollowService.instance.loadData, ), ), ), ], ), ); } List buildAppbarActions(BuildContext context) { return [ IconButton( onPressed: () { showMore(); }, icon: const Icon(Icons.more_horiz), ), ]; } void showMore() { showModalBottomSheet( context: Get.context!, constraints: const BoxConstraints( maxWidth: 600, ), isScrollControlled: true, builder: (_) => Container( padding: EdgeInsets.only( bottom: AppStyle.bottomBarHeight, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.refresh), title: const Text("刷新"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.refreshRoom(); }, ), ListTile( leading: const Icon(Icons.play_circle_outline), trailing: const Icon(Icons.chevron_right), title: const Text("切换清晰度"), onTap: () { Get.back(); controller.showQualitySheet(); }, ), ListTile( leading: const Icon(Icons.switch_video_outlined), title: const Text("切换线路"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.showPlayUrlsSheet(); }, ), ListTile( leading: const Icon(Icons.aspect_ratio_outlined), title: const Text("画面尺寸"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.showPlayerSettingsSheet(); }, ), ListTile( leading: const Icon(Icons.camera_alt_outlined), title: const Text("截图"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.saveScreenshot(); }, ), Visibility( visible: Platform.isAndroid, child: ListTile( leading: const Icon(Icons.picture_in_picture), title: const Text("小窗播放"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.enablePIP(); }, ), ), ListTile( leading: const Icon(Icons.timer_outlined), title: const Text("定时关闭"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.showAutoExitSheet(); }, ), ListTile( leading: const Icon(Icons.share_sharp), title: const Text("分享直播间"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.share(); }, ), ListTile( leading: const Icon(Icons.copy), title: const Text("复制链接"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.copyUrl(); }, ), ListTile( leading: const Icon(Icons.open_in_new), title: const Text("APP中打开"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.openNaviteAPP(); }, ), ListTile( leading: const Icon(Icons.info_outline_rounded), title: const Text("播放信息"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); controller.showDebugInfo(); }, ), ], ), ), ); } String parseDuration(int sec) { // 转为时分秒 var h = sec ~/ 3600; var m = (sec % 3600) ~/ 60; var s = sec % 60; if (h > 0) { return "${h.toString().padLeft(2, '0')}小时${m.toString().padLeft(2, '0')}分钟${s.toString().padLeft(2, '0')}秒"; } if (m > 0) { return "${m.toString().padLeft(2, '0')}分钟${s.toString().padLeft(2, '0')}秒"; } return "${s.toString().padLeft(2, '0')}秒"; } } ================================================ FILE: simple_live_app/lib/modules/live_room/player/player_controller.dart ================================================ import 'dart:async'; import 'dart:io'; import 'package:auto_orientation_v2/auto_orientation_v2.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:file_picker/file_picker.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:image_gallery_saver_plus/image_gallery_saver_plus.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:volume_controller/volume_controller.dart'; import 'package:screen_brightness/screen_brightness.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/custom_throttle.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; import 'package:window_manager/window_manager.dart'; mixin PlayerMixin { GlobalKey globalPlayerKey = GlobalKey(); GlobalKey globalDanmuKey = GlobalKey(); /// 播放器实例 late final player = Player( configuration: PlayerConfiguration( title: "Simple Live Player", logLevel: AppSettingsController.instance.logEnable.value ? MPVLogLevel.info : MPVLogLevel.error, ), ); /// 初始化播放器并设置 ao 参数 Future initializePlayer() async { var pp = player.platform as NativePlayer; // 设置音频输出驱动 if (AppSettingsController.instance.customPlayerOutput.value) { if (player.platform is NativePlayer) { await (player.platform as dynamic).setProperty( 'ao', AppSettingsController.instance.audioOutputDriver.value, ); } } // media_kit 仓库更新导致的问题,临时解决办法 if(Platform.isAndroid){ await pp.setProperty('force-seekable', 'yes'); } } /// 视频控制器 late final videoController = VideoController( player, configuration: AppSettingsController.instance.customPlayerOutput.value ? VideoControllerConfiguration( vo: AppSettingsController.instance.videoOutputDriver.value, hwdec: AppSettingsController.instance.videoHardwareDecoder.value, ) : AppSettingsController.instance.playerCompatMode.value ? const VideoControllerConfiguration( vo: 'mediacodec_embed', hwdec: 'mediacodec', ) : VideoControllerConfiguration( enableHardwareAcceleration: AppSettingsController.instance.hardwareDecode.value, androidAttachSurfaceAfterVideoParameters: false, ), ); } mixin PlayerStateMixin on PlayerMixin { ///音量控制条计时器 Timer? hidevolumeTimer; /// 是否进入桌面端小窗 RxBool smallWindowState = false.obs; /// 是否显示弹幕 RxBool showDanmakuState = false.obs; /// 是否显示控制器 RxBool showControlsState = false.obs; /// 是否显示设置窗口 RxBool showSettingState = false.obs; /// 是否显示弹幕设置窗口 RxBool showDanmakuSettingState = false.obs; /// 是否处于锁定控制器状态 RxBool lockControlsState = false.obs; /// 是否处于全屏状态 RxBool fullScreenState = false.obs; /// 显示手势Tip RxBool showGestureTip = false.obs; /// 手势Tip文本 RxString gestureTipText = "".obs; /// 显示提示底部Tip RxBool showBottomTip = false.obs; /// 提示底部Tip文本 RxString bottomTipText = "".obs; /// 自动隐藏控制器计时器 Timer? hideControlsTimer; /// 自动隐藏提示计时器 Timer? hideSeekTipTimer; /// 是否为竖屏直播间 var isVertical = false.obs; Widget? danmakuView; var showQualites = false.obs; var showLines = false.obs; /// 隐藏控制器 void hideControls() { showControlsState.value = false; hideControlsTimer?.cancel(); } void setLockState() { lockControlsState.value = !lockControlsState.value; if (lockControlsState.value) { showControlsState.value = false; } else { showControlsState.value = true; } } /// 显示控制器 void showControls() { showControlsState.value = true; resetHideControlsTimer(); } /// 开始隐藏控制器计时 /// - 当点击控制器上时功能时需要重新计时 void resetHideControlsTimer() { hideControlsTimer?.cancel(); hideControlsTimer = Timer( const Duration( seconds: 5, ), hideControls, ); } void updateScaleMode() { var boxFit = BoxFit.contain; double? aspectRatio; if (player.state.width != null && player.state.height != null) { aspectRatio = player.state.width! / player.state.height!; } if (AppSettingsController.instance.scaleMode.value == 0) { boxFit = BoxFit.contain; } else if (AppSettingsController.instance.scaleMode.value == 1) { boxFit = BoxFit.fill; } else if (AppSettingsController.instance.scaleMode.value == 2) { boxFit = BoxFit.cover; } else if (AppSettingsController.instance.scaleMode.value == 3) { boxFit = BoxFit.contain; aspectRatio = 16 / 9; } else if (AppSettingsController.instance.scaleMode.value == 4) { boxFit = BoxFit.contain; aspectRatio = 4 / 3; } globalPlayerKey.currentState?.update( aspectRatio: aspectRatio, fit: boxFit, ); } } mixin PlayerDanmakuMixin on PlayerStateMixin { /// 弹幕控制器 DanmakuController? danmakuController; void initDanmakuController(DanmakuController e) { danmakuController = e; // danmakuController?.updateOption( // DanmakuOption( // fontSize: AppSettingsController.instance.danmuSize.value, // area: AppSettingsController.instance.danmuArea.value, // duration: AppSettingsController.instance.danmuSpeed.value, // opacity: AppSettingsController.instance.danmuOpacity.value, // strokeWidth: AppSettingsController.instance.danmuStrokeWidth.value, // fontWeight: FontWeight // .values[AppSettingsController.instance.danmuFontWeight.value], // ), // ); } void updateDanmuOption(DanmakuOption? option) { if (danmakuController == null || option == null) return; danmakuController!.updateOption(option); } void disposeDanmakuController() { danmakuController?.clear(); } void addDanmaku(List items) { if (!showDanmakuState.value) { return; } for (var item in items) { danmakuController?.addDanmaku(item); } } } mixin PlayerSystemMixin on PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin { final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); final pip = Floating(); StreamSubscription? _pipSubscription; //final VolumeController volumeController = VolumeController(); /// 初始化一些系统状态 void initSystem() async { if (Platform.isAndroid || Platform.isIOS) { VolumeController.instance.showSystemUI = false; } // 屏幕常亮 //WakelockPlus.enable(); // 开始隐藏计时 resetHideControlsTimer(); // 进入全屏模式 if (AppSettingsController.instance.autoFullScreen.value) { enterFullScreen(); } } /// 释放一些系统状态 Future resetSystem() async { _pipSubscription?.cancel(); //pip.dispose(); await SystemChrome.setEnabledSystemUIMode( SystemUiMode.edgeToEdge, overlays: SystemUiOverlay.values, ); await setPortraitOrientation(); if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) { // 亮度重置,桌面平台可能会报错,暂时不处理桌面平台的亮度 try { await ScreenBrightness.instance.resetApplicationScreenBrightness(); } catch (e) { Log.logPrint(e); } } await WakelockPlus.disable(); } /// 进入全屏 void enterFullScreen() { fullScreenState.value = true; if (Platform.isAndroid || Platform.isIOS) { //全屏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); if (!isVertical.value) { //横屏 setLandscapeOrientation(); } } else { windowManager.setFullScreen(true); } //danmakuController?.clear(); } /// 退出全屏 void exitFull() { if (Platform.isAndroid || Platform.isIOS) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge, overlays: SystemUiOverlay.values); setPortraitOrientation(); } else { windowManager.setFullScreen(false); } fullScreenState.value = false; //danmakuController?.clear(); } Size? _lastWindowSize; Offset? _lastWindowPosition; ///小窗模式() void enterSmallWindow() async { if (!(Platform.isAndroid || Platform.isIOS)) { fullScreenState.value = true; smallWindowState.value = true; // 读取窗口大小 _lastWindowSize = await windowManager.getSize(); _lastWindowPosition = await windowManager.getPosition(); windowManager.setTitleBarStyle(TitleBarStyle.hidden); // 获取视频窗口大小 var width = player.state.width ?? 16; var height = player.state.height ?? 9; // 横屏还是竖屏 if (height > width) { var aspectRatio = width / height; windowManager.setSize(Size(400, 400 / aspectRatio)); } else { var aspectRatio = height / width; windowManager.setSize(Size(280 / aspectRatio, 280)); } windowManager.setAlwaysOnTop(true); } } ///退出小窗模式() void exitSmallWindow() { if (!(Platform.isAndroid || Platform.isIOS)) { fullScreenState.value = false; smallWindowState.value = false; windowManager.setTitleBarStyle(TitleBarStyle.normal); windowManager.setSize(_lastWindowSize!); windowManager.setPosition(_lastWindowPosition!); windowManager.setAlwaysOnTop(false); //windowManager.setAlignment(Alignment.center); } } /// 设置横屏 Future setLandscapeOrientation() async { if (await beforeIOS16()) { AutoOrientation.landscapeAutoMode(); } else { SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); } } /// 设置竖屏 Future setPortraitOrientation() async { if (await beforeIOS16()) { AutoOrientation.portraitAutoMode(); } else { await SystemChrome.setPreferredOrientations(DeviceOrientation.values); } } /// 是否是IOS16以下 Future beforeIOS16() async { if (Platform.isIOS) { var info = await deviceInfo.iosInfo; var version = info.systemVersion; var versionInt = int.tryParse(version.split('.').first) ?? 0; return versionInt < 16; } else { return false; } } Future saveScreenshot() async { try { SmartDialog.showLoading(msg: "正在保存截图"); //检查相册权限,仅iOS需要 var permission = await Utils.checkPhotoPermission(); if (!permission) { SmartDialog.showToast("没有相册权限"); SmartDialog.dismiss(status: SmartStatus.loading); return; } var imageData = await player.screenshot(); if (imageData == null) { SmartDialog.showToast("截图失败,数据为空"); SmartDialog.dismiss(status: SmartStatus.loading); return; } if (Platform.isIOS || Platform.isAndroid) { await ImageGallerySaverPlus.saveImage( imageData, ); SmartDialog.showToast("已保存截图至相册"); } else { //选择保存文件夹 var path = await FilePicker.platform.saveFile( allowedExtensions: ["jpg"], type: FileType.image, fileName: "${DateTime.now().millisecondsSinceEpoch}.jpg", ); if (path == null) { SmartDialog.showToast("取消保存"); SmartDialog.dismiss(status: SmartStatus.loading); return; } var file = File(path); await file.writeAsBytes(imageData); SmartDialog.showToast("已保存截图至${file.path}"); } } catch (e) { Log.logPrint(e); SmartDialog.showToast("截图失败"); } finally { SmartDialog.dismiss(status: SmartStatus.loading); } } /// 开启小窗播放前弹幕状态 bool danmakuStateBeforePIP = false; Future enablePIP() async { if (!Platform.isAndroid) { return; } if (await pip.isPipAvailable == false) { SmartDialog.showToast("设备不支持小窗播放"); return; } danmakuStateBeforePIP = showDanmakuState.value; //关闭并清除弹幕 if (AppSettingsController.instance.pipHideDanmu.value && danmakuStateBeforePIP) { showDanmakuState.value = false; } danmakuController?.clear(); //关闭控制器 showControlsState.value = false; //监听事件 var width = player.state.width ?? 0; var height = player.state.height ?? 0; Rational ratio = const Rational.landscape(); if (height > width) { ratio = const Rational.vertical(); } else { ratio = const Rational.landscape(); } await pip.enable( ImmediatePiP( aspectRatio: ratio, ), ); _pipSubscription ??= pip.pipStatusStream.listen((event) { if (event == PiPStatus.disabled) { danmakuController?.clear(); showDanmakuState.value = danmakuStateBeforePIP; } Log.w(event.toString()); }); } } mixin PlayerGestureControlMixin on PlayerStateMixin, PlayerMixin, PlayerSystemMixin { /// 单击显示/隐藏控制器 void onTap() { if (showControlsState.value) { hideControls(); } else { showControls(); } } //桌面端操控 void onEnter(PointerEnterEvent event) { if (!showControlsState.value) { showControls(); } } void onExit(PointerExitEvent event) { if (showControlsState.value) { hideControls(); } } void onHover(PointerHoverEvent event, BuildContext context) { final screenHeight = MediaQuery.of(context).size.height; final targetPosition = screenHeight * 0.25; // 计算屏幕顶部25%的位置 if (event.position.dy <= targetPosition || event.position.dy >= targetPosition * 3) { if (!showControlsState.value) { showControls(); } } } /// 双击全屏/退出全屏 void onDoubleTap(TapDownDetails details) { if (lockControlsState.value) { return; } if (fullScreenState.value) { exitFull(); } else { enterFullScreen(); } } bool verticalDragging = false; bool leftVerticalDrag = false; var _currentVolume = 0.0; var _currentBrightness = 1.0; var verStartPosition = 0.0; DelayedThrottle? throttle; /// 竖向手势开始 void onVerticalDragStart(DragStartDetails details) async { if (lockControlsState.value && fullScreenState.value) { return; } final dy = details.globalPosition.dy; // 开始位置必须是中间2/4的位置 if (dy < Get.height * 0.25 || dy > Get.height * 0.75) { return; } verStartPosition = dy; leftVerticalDrag = details.globalPosition.dx < Get.width / 2; throttle = DelayedThrottle(200); verticalDragging = true; if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) { showGestureTip.value = true; } if (Platform.isAndroid || Platform.isIOS) { _currentVolume = await VolumeController.instance.getVolume(); } if (Platform.isAndroid || Platform.isIOS || Platform.isMacOS) { _currentBrightness = await ScreenBrightness.instance.application; } } /// 竖向手势更新 void onVerticalDragUpdate(DragUpdateDetails e) async { if (lockControlsState.value && fullScreenState.value) { return; } if (verticalDragging == false) return; if (!Platform.isAndroid && !Platform.isIOS) { return; } //String text = ""; //double value = 0.0; Log.logPrint("$verStartPosition/${e.globalPosition.dy}"); if (leftVerticalDrag) { setGestureBrightness(e.globalPosition.dy); } else { setGestureVolume(e.globalPosition.dy); } } int lastVolume = -1; // it's ok to be -1 void setGestureVolume(double dy) { double value = 0.0; double seek; if (dy > verStartPosition) { value = ((dy - verStartPosition) / (Get.height * 0.5)); seek = _currentVolume - value; if (seek < 0) { seek = 0; } } else { value = ((dy - verStartPosition) / (Get.height * 0.5)); seek = value.abs() + _currentVolume; if (seek > 1) { seek = 1; } } int volume = _convertVolume((seek * 100).round()); if (volume == lastVolume) { return; } lastVolume = volume; // update UI outside throttle to make it more fluent gestureTipText.value = "音量 $volume%"; throttle?.invoke(() async => await _realSetVolume(volume)); } // 0 to 100, 5 step each int _convertVolume(int volume) { return (volume / 5).round() * 5; } Future _realSetVolume(int volume) async { Log.logPrint(volume); VolumeController.instance.setVolume(volume / 100); } void setGestureBrightness(double dy) { double value = 0.0; if (dy > verStartPosition) { value = ((dy - verStartPosition) / (Get.height * 0.5)); var seek = _currentBrightness - value; if (seek < 0) { seek = 0; } ScreenBrightness.instance.setApplicationScreenBrightness(seek); gestureTipText.value = "亮度 ${(seek * 100).toInt()}%"; Log.logPrint(value); } else { value = ((dy - verStartPosition) / (Get.height * 0.5)); var seek = value.abs() + _currentBrightness; if (seek > 1) { seek = 1; } ScreenBrightness.instance.setApplicationScreenBrightness(seek); gestureTipText.value = "亮度 ${(seek * 100).toInt()}%"; Log.logPrint(value); } } /// 竖向手势完成 void onVerticalDragEnd(DragEndDetails details) async { if (lockControlsState.value && fullScreenState.value) { return; } throttle = null; verticalDragging = false; leftVerticalDrag = false; showGestureTip.value = false; } } class PlayerController extends BaseController with PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin, PlayerSystemMixin, PlayerGestureControlMixin { @override void onInit() { initSystem(); initStream(); //设置音量 player.setVolume(AppSettingsController.instance.playerVolume.value); super.onInit(); } StreamSubscription? _errorSubscription; StreamSubscription? _completedSubscription; StreamSubscription? _widthSubscription; StreamSubscription? _heightSubscription; StreamSubscription? _logSubscription; StreamSubscription? _playingSubscription; void initStream() { _errorSubscription = player.stream.error.listen((event) { Log.d("播放器错误:$event"); // 跳过无音频输出的错误 // Could not open/initialize audio device -> no sound. if (event.contains('no sound.')) { return; } //SmartDialog.showToast(event); mediaError(event); }); _playingSubscription = player.stream.playing.listen((event) { if (event) { WakelockPlus.enable(); Log.d("Playing"); } }); _completedSubscription = player.stream.completed.listen((event) { if (event) { mediaEnd(); } }); _logSubscription = player.stream.log.listen((event) { Log.d("播放器日志:$event"); }); _widthSubscription = player.stream.width.listen((event) { Log.d( 'width:$event W:${(player.state.width)} H:${(player.state.height)}'); isVertical.value = (player.state.height ?? 9) > (player.state.width ?? 16); }); _heightSubscription = player.stream.height.listen((event) { Log.d( 'height:$event W:${(player.state.width)} H:${(player.state.height)}'); isVertical.value = (player.state.height ?? 9) > (player.state.width ?? 16); }); } void disposeStream() { _errorSubscription?.cancel(); _completedSubscription?.cancel(); _widthSubscription?.cancel(); _heightSubscription?.cancel(); _logSubscription?.cancel(); _pipSubscription?.cancel(); _playingSubscription?.cancel(); } void mediaEnd() { WakelockPlus.disable(); } void mediaError(String error) { WakelockPlus.disable(); } void showDebugInfo() { Utils.showBottomSheet( title: "播放信息", child: ListView( children: [ ListTile( title: const Text("Resolution"), subtitle: Text('${player.state.width}x${player.state.height}'), onTap: () { Clipboard.setData( ClipboardData( text: "Resolution\n${player.state.width}x${player.state.height}", ), ); }, ), ListTile( title: const Text("VideoParams"), subtitle: Text(player.state.videoParams.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "VideoParams\n${player.state.videoParams}", ), ); }, ), ListTile( title: const Text("AudioParams"), subtitle: Text(player.state.audioParams.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "AudioParams\n${player.state.audioParams}", ), ); }, ), ListTile( title: const Text("Media"), subtitle: Text(player.state.playlist.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "Media\n${player.state.playlist}", ), ); }, ), ListTile( title: const Text("AudioTrack"), subtitle: Text(player.state.track.audio.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "AudioTrack\n${player.state.track.audio}", ), ); }, ), ListTile( title: const Text("VideoTrack"), subtitle: Text(player.state.track.video.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "VideoTrack\n${player.state.track.audio}", ), ); }, ), ListTile( title: const Text("AudioBitrate"), subtitle: Text(player.state.audioBitrate.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "AudioBitrate\n${player.state.audioBitrate}", ), ); }, ), ListTile( title: const Text("Volume"), subtitle: Text(player.state.volume.toString()), onTap: () { Clipboard.setData( ClipboardData( text: "Volume\n${player.state.volume}", ), ); }, ), ], ), ); } @override void onClose() async { Log.w("播放器关闭"); if (smallWindowState.value) { exitSmallWindow(); } disposeStream(); disposeDanmakuController(); await resetSystem(); await player.dispose(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/live_room/player/player_controls.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/live_room/live_room_controller.dart'; import 'package:simple_live_app/modules/settings/danmu_settings_page.dart'; import 'package:simple_live_app/services/follow_service.dart'; import 'package:simple_live_app/widgets/desktop_refresh_button.dart'; import 'package:simple_live_app/widgets/follow_user_item.dart'; import 'package:window_manager/window_manager.dart'; import 'package:simple_live_app/widgets/superchat_card.dart'; import 'dart:async'; import 'package:simple_live_core/simple_live_core.dart'; Widget playerControls( VideoState videoState, LiveRoomController controller, ) { return Obx(() { if (controller.fullScreenState.value) { return buildFullControls( videoState, controller, ); } return buildControls( videoState.context.orientation == Orientation.portrait, videoState, controller, ); }); } Widget buildFullControls( VideoState videoState, LiveRoomController controller, ) { var padding = MediaQuery.of(videoState.context).padding; GlobalKey volumeButtonkey = GlobalKey(); return DragToMoveArea( child: Stack( children: [ Container(), buildDanmuView(videoState, controller), // 左下角SC显示 Obx( () => Visibility( visible: AppSettingsController.instance.playershowSuperChat.value && ((!Platform.isAndroid && !Platform.isIOS) || controller.fullScreenState.value), child: Positioned( left: 24, bottom: 24, child: PlayerSuperChatOverlay(controller: controller), ), ), ), Center( child: // 中间 StreamBuilder( stream: videoState.widget.controller.player.stream.buffering, initialData: videoState.widget.controller.player.state.buffering, builder: (_, s) => Visibility( visible: s.data ?? false, child: const Center( child: CircularProgressIndicator(), ), ), ), ), Positioned.fill( child: GestureDetector( onTap: controller.onTap, onDoubleTapDown: controller.onDoubleTap, onLongPress: () { if (controller.lockControlsState.value) { return; } showFollowUser(controller); }, onVerticalDragStart: controller.onVerticalDragStart, onVerticalDragUpdate: controller.onVerticalDragUpdate, onVerticalDragEnd: controller.onVerticalDragEnd, child: MouseRegion( onHover: (PointerHoverEvent event) { controller.onHover(event, videoState.context); }, child: Container( width: double.infinity, height: double.infinity, color: Colors.transparent, // child: Visibility( // //拖拽区域 // visible: controller.smallWindowState.value, // child: DragToMoveArea( // child: Container( // width: double.infinity, // height: double.infinity, // color: Colors.transparent, // )), // ), ), ), ), ), // 顶部 Obx( () => AnimatedPositioned( left: 0, right: 0, top: (controller.showControlsState.value && !controller.lockControlsState.value) ? 0 : -(48 + padding.top), duration: const Duration(milliseconds: 200), child: Container( height: 48 + padding.top, padding: EdgeInsets.only( left: padding.left + 12, right: padding.right + 12, top: padding.top, ), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [ Colors.transparent, Colors.black87, ], ), ), child: Row( children: [ IconButton( onPressed: () { if (controller.smallWindowState.value) { controller.exitSmallWindow(); } else { controller.exitFull(); } }, icon: const Icon( Icons.arrow_back, color: Colors.white, size: 24, ), ), AppStyle.hGap12, Expanded( child: Text( "${controller.detail.value?.title} - ${controller.detail.value?.userName}", maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.white, fontSize: 16), ), ), AppStyle.hGap12, IconButton( onPressed: () { controller.saveScreenshot(); }, icon: const Icon( Icons.camera_alt_outlined, color: Colors.white, size: 24, ), ), IconButton( onPressed: () { showFollowUser(controller); }, icon: const Icon( Remix.play_list_2_line, color: Colors.white, size: 24, ), ), Visibility( visible: Platform.isAndroid, child: IconButton( onPressed: () { controller.enablePIP(); }, icon: const Icon( Icons.picture_in_picture, color: Colors.white, size: 24, ), ), ), IconButton( onPressed: () { showPlayerSettings(controller); }, icon: const Icon( Icons.more_horiz, color: Colors.white, size: 24, ), ), ], ), ), ), ), // 底部 Obx( () => AnimatedPositioned( left: 0, right: 0, bottom: (controller.showControlsState.value && !controller.lockControlsState.value) ? 0 : -(80 + padding.bottom), duration: const Duration(milliseconds: 200), child: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.transparent, Colors.black87, ], ), ), padding: EdgeInsets.only( left: padding.left + 12, right: padding.right + 12, bottom: padding.bottom, ), child: Row( children: [ IconButton( onPressed: () { controller.refreshRoom(); }, icon: const Icon( Remix.refresh_line, color: Colors.white, ), ), Offstage( offstage: controller.showDanmakuState.value, child: IconButton( onPressed: () => controller.showDanmakuState.value = !controller.showDanmakuState.value, icon: const ImageIcon( AssetImage('assets/icons/icon_danmaku_open.png'), size: 24, color: Colors.white, ), ), ), Offstage( offstage: !controller.showDanmakuState.value, child: IconButton( onPressed: () => controller.showDanmakuState.value = !controller.showDanmakuState.value, icon: const ImageIcon( AssetImage('assets/icons/icon_danmaku_close.png'), size: 24, color: Colors.white, ), ), ), IconButton( onPressed: () { showDanmakuSettings(controller); }, icon: const ImageIcon( AssetImage('assets/icons/icon_danmaku_setting.png'), size: 24, color: Colors.white, ), ), Obx( () => Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( controller.liveDuration.value, style: const TextStyle(fontSize: 14, color: Colors.white), ), ), ), const Expanded(child: Center()), Visibility( visible: !Platform.isAndroid && !Platform.isIOS, child: IconButton( key: volumeButtonkey, onPressed: () { controller .showVolumeSlider(volumeButtonkey.currentContext!); }, icon: const Icon( Icons.volume_down, size: 24, color: Colors.white, ), ), ), TextButton( onPressed: () { showQualitesInfo(controller); }, child: Obx( () => Text( controller.currentQualityInfo.value, style: const TextStyle(color: Colors.white, fontSize: 15), ), ), ), TextButton( onPressed: () { showLinesInfo(controller); }, child: Text( controller.currentLineInfo.value, style: const TextStyle(color: Colors.white, fontSize: 15), ), ), IconButton( onPressed: () { if (controller.smallWindowState.value) { controller.exitSmallWindow(); } else { controller.exitFull(); } }, icon: const Icon( Remix.fullscreen_exit_fill, color: Colors.white, ), ), ], ), ), ), ), // 右侧锁定 Obx( () => AnimatedPositioned( top: 0, bottom: 0, right: controller.showControlsState.value ? padding.right + 12 : -(64 + padding.right), duration: const Duration(milliseconds: 200), child: buildLockButton(controller), ), ), // 左侧锁定 Obx( () => AnimatedPositioned( top: 0, bottom: 0, left: controller.showControlsState.value ? padding.left + 12 : -(64 + padding.right), duration: const Duration(milliseconds: 200), child: buildLockButton(controller), ), ), Obx( () => Offstage( offstage: !controller.showGestureTip.value, child: Center( child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey.shade900, borderRadius: BorderRadius.circular(12), ), child: Text( controller.gestureTipText.value, style: const TextStyle(fontSize: 18, color: Colors.white), ), ), ), ), ), ], ), ); } Widget buildLockButton(LiveRoomController controller) { return Center( child: InkWell( onTap: () { controller.setLockState(); }, child: Container( decoration: BoxDecoration( color: Colors.black45, borderRadius: AppStyle.radius8, ), width: 40, height: 40, child: Center( child: Icon( controller.lockControlsState.value ? Icons.lock_outline_rounded : Icons.lock_open_outlined, color: Colors.white, size: 20, ), ), ), ), ); } Widget buildControls( bool isPortrait, VideoState videoState, LiveRoomController controller, ) { GlobalKey volumeButtonkey = GlobalKey(); return Stack( children: [ Container(), buildDanmuView(videoState, controller), // 左下角SC显示 Obx( () => Visibility( visible: AppSettingsController.instance.playershowSuperChat.value && ((!Platform.isAndroid && !Platform.isIOS) || controller.fullScreenState.value), child: Positioned( left: 24, bottom: 24, child: PlayerSuperChatOverlay(controller: controller), ), ), ), // 中间 Center( child: StreamBuilder( stream: videoState.widget.controller.player.stream.buffering, initialData: videoState.widget.controller.player.state.buffering, builder: (_, s) => Visibility( visible: s.data ?? false, child: const Center( child: CircularProgressIndicator(), ), ), ), ), Positioned.fill( child: GestureDetector( onTap: controller.onTap, onDoubleTapDown: controller.onDoubleTap, onVerticalDragStart: controller.onVerticalDragStart, onVerticalDragUpdate: controller.onVerticalDragUpdate, onVerticalDragEnd: controller.onVerticalDragEnd, //onLongPress: controller.showDebugInfo, child: MouseRegion( onEnter: controller.onEnter, child: Container( width: double.infinity, height: double.infinity, color: Colors.transparent, ), ), ), ), Obx( () => AnimatedPositioned( left: 0, right: 0, bottom: controller.showControlsState.value ? 0 : -48, duration: const Duration(milliseconds: 200), child: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.transparent, Colors.black87, ], ), ), child: Row( children: [ IconButton( onPressed: () { controller.refreshRoom(); }, icon: const Icon( Remix.refresh_line, color: Colors.white, ), ), Offstage( offstage: controller.showDanmakuState.value, child: IconButton( onPressed: () => controller.showDanmakuState.value = !controller.showDanmakuState.value, icon: const ImageIcon( AssetImage('assets/icons/icon_danmaku_open.png'), size: 24, color: Colors.white, ), ), ), Offstage( offstage: !controller.showDanmakuState.value, child: IconButton( onPressed: () => controller.showDanmakuState.value = !controller.showDanmakuState.value, icon: const ImageIcon( AssetImage('assets/icons/icon_danmaku_close.png'), size: 24, color: Colors.white, ), ), ), IconButton( onPressed: () { controller.showDanmuSettingsSheet(); }, icon: const ImageIcon( AssetImage('assets/icons/icon_danmaku_setting.png'), size: 24, color: Colors.white, ), ), Obx( () => Padding( padding: const EdgeInsets.only(left: 8.0), child: Text( controller.liveDuration.value, style: const TextStyle(fontSize: 14, color: Colors.white), ), ), ), const Expanded(child: Center()), Visibility( visible: !Platform.isAndroid && !Platform.isIOS, child: IconButton( key: volumeButtonkey, onPressed: () { controller.showVolumeSlider( volumeButtonkey.currentContext!, ); }, icon: const Icon( Icons.volume_down, size: 24, color: Colors.white, ), ), ), Offstage( offstage: isPortrait, child: TextButton( onPressed: () { controller.showQualitySheet(); }, child: Obx( () => Text( controller.currentQualityInfo.value, style: const TextStyle(color: Colors.white, fontSize: 15), ), ), ), ), Offstage( offstage: isPortrait, child: TextButton( onPressed: () { controller.showPlayUrlsSheet(); }, child: Text( controller.currentLineInfo.value, style: const TextStyle(color: Colors.white, fontSize: 15), ), ), ), Visibility( visible: !Platform.isAndroid && !Platform.isIOS, child: IconButton( onPressed: () { controller.enterSmallWindow(); }, icon: const Icon( Icons.picture_in_picture, color: Colors.white, size: 24, ), ), ), IconButton( onPressed: () { controller.enterFullScreen(); }, icon: const Icon( Remix.fullscreen_line, color: Colors.white, ), ), ], ), ), ), ), Obx( () => Offstage( offstage: !controller.showGestureTip.value, child: Center( child: Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.grey.shade900, borderRadius: BorderRadius.circular(12), ), child: Text( controller.gestureTipText.value, style: const TextStyle(fontSize: 18, color: Colors.white), ), ), ), ), ), ], ); } Widget buildDanmuView(VideoState videoState, LiveRoomController controller) { var padding = MediaQuery.of(videoState.context).padding; controller.danmakuView ??= DanmakuScreen( key: controller.globalDanmuKey, createdController: controller.initDanmakuController, option: DanmakuOption( fontSize: AppSettingsController.instance.danmuSize.value, area: AppSettingsController.instance.danmuArea.value, duration: AppSettingsController.instance.danmuSpeed.value.toInt(), opacity: AppSettingsController.instance.danmuOpacity.value, //strokeWidth: AppSettingsController.instance.danmuStrokeWidth.value, fontWeight: AppSettingsController.instance.danmuFontWeight.value, ), ); return Positioned.fill( top: padding.top, bottom: padding.bottom, child: Obx( () => Offstage( offstage: !controller.showDanmakuState.value, child: Padding( padding: controller.fullScreenState.value ? EdgeInsets.only( top: AppSettingsController.instance.danmuTopMargin.value, bottom: AppSettingsController.instance.danmuBottomMargin.value, ) : EdgeInsets.zero, child: controller.danmakuView!, ), ), ), ); } void showLinesInfo(LiveRoomController controller) { if (controller.isVertical.value) { controller.showPlayUrlsSheet(); return; } Utils.showRightDialog( title: "线路", useSystem: true, child: ListView.builder( padding: EdgeInsets.zero, itemCount: controller.playUrls.length, itemBuilder: (_, i) { return ListTile( selected: controller.currentLineIndex == i, title: Text.rich( TextSpan( text: "线路${i + 1}", children: [ WidgetSpan( child: Container( decoration: BoxDecoration( borderRadius: AppStyle.radius4, border: Border.all( color: Colors.grey, ), ), padding: AppStyle.edgeInsetsH4, margin: AppStyle.edgeInsetsL8, child: Text( controller.playUrls[i].contains(".flv") ? "FLV" : "HLS", style: const TextStyle( fontSize: 12, ), ), )), ], ), style: const TextStyle(fontSize: 14), ), minLeadingWidth: 16, onTap: () { Utils.hideRightDialog(); //controller.currentLineIndex = i; //controller.setPlayer(); controller.changePlayLine(i); }, ); }, ), ); } void showQualitesInfo(LiveRoomController controller) { if (controller.isVertical.value) { controller.showQualitySheet(); return; } Utils.showRightDialog( title: "清晰度", useSystem: true, child: ListView.builder( padding: EdgeInsets.zero, itemCount: controller.qualites.length, itemBuilder: (_, i) { var item = controller.qualites[i]; return ListTile( selected: controller.currentQuality == i, title: Text( item.quality, style: const TextStyle(fontSize: 14), ), minLeadingWidth: 16, onTap: () { Utils.hideRightDialog(); controller.currentQuality = i; controller.getPlayUrl(); }, ); }, ), ); } void showDanmakuSettings(LiveRoomController controller) { if (controller.isVertical.value) { controller.showDanmuSettingsSheet(); return; } Utils.showRightDialog( title: "弹幕设置", width: 400, useSystem: true, child: ListView( padding: AppStyle.edgeInsetsA12, children: [ DanmuSettingsView( danmakuController: controller.danmakuController, ), ], ), ); } void showPlayerSettings(LiveRoomController controller) { if (controller.isVertical.value) { controller.showPlayerSettingsSheet(); return; } Utils.showRightDialog( title: "设置", width: 320, useSystem: true, child: Obx( () => RadioGroup( groupValue: AppSettingsController.instance.scaleMode.value, onChanged: (e) { AppSettingsController.instance.setScaleMode(e ?? 0); controller.updateScaleMode(); }, child: ListView( padding: AppStyle.edgeInsetsV12, children: [ Padding( padding: AppStyle.edgeInsetsH16, child: Text( "画面尺寸", style: Get.textTheme.titleMedium, ), ), const RadioListTile( value: 0, contentPadding: AppStyle.edgeInsetsH4, title: Text("适应"), visualDensity: VisualDensity.compact, ), const RadioListTile( value: 1, contentPadding: AppStyle.edgeInsetsH4, title: Text("拉伸"), visualDensity: VisualDensity.compact, ), const RadioListTile( value: 2, contentPadding: AppStyle.edgeInsetsH4, title: Text("铺满"), visualDensity: VisualDensity.compact, ), const RadioListTile( value: 3, contentPadding: AppStyle.edgeInsetsH4, title: Text("16:9"), visualDensity: VisualDensity.compact, ), const RadioListTile( value: 4, contentPadding: AppStyle.edgeInsetsH4, title: Text("4:3"), visualDensity: VisualDensity.compact, ), ], ), ), ), ); } void showFollowUser(LiveRoomController controller) { if (controller.isVertical.value) { controller.showFollowUserSheet(); return; } Utils.showRightDialog( title: "关注列表", width: 400, useSystem: true, child: Obx( () => Stack( children: [ RefreshIndicator( onRefresh: FollowService.instance.loadData, child: ListView.builder( itemCount: FollowService.instance.liveList.length, itemBuilder: (_, i) { var item = FollowService.instance.liveList[i]; return Obx( () => FollowUserItem( item: item, playing: controller.rxSite.value.id == item.siteId && controller.rxRoomId.value == item.roomId, onTap: () { Utils.hideRightDialog(); controller.resetRoom( Sites.allSites[item.siteId]!, item.roomId, ); }, ), ); }, ), ), if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) Positioned( right: 12, bottom: 12, child: Obx( () => DesktopRefreshButton( refreshing: FollowService.instance.updating.value, onPressed: FollowService.instance.loadData, ), ), ), ], ), ), ); } class PlayerSuperChatCard extends StatefulWidget { final LiveSuperChatMessage message; final VoidCallback onExpire; final int duration; const PlayerSuperChatCard( {required this.message, required this.onExpire, required this.duration, Key? key}) : super(key: key); @override State createState() => _PlayerSuperChatCardState(); } class _PlayerSuperChatCardState extends State { late Timer timer; late int countdown; @override void initState() { super.initState(); countdown = widget.duration; timer = Timer.periodic(const Duration(seconds: 1), (t) { if (countdown <= 1) { widget.onExpire(); timer.cancel(); return; } setState(() { countdown -= 1; }); }); } @override void dispose() { timer.cancel(); super.dispose(); } @override Widget build(BuildContext context) { return Opacity( opacity: 0.65, child: SuperChatCard( widget.message, onExpire: () {}, customCountdown: countdown, ), ); } } class LocalDisplaySC { final LiveSuperChatMessage sc; final DateTime expireAt; final int duration; LocalDisplaySC(this.sc, this.expireAt, this.duration); } class PlayerSuperChatOverlay extends StatefulWidget { final LiveRoomController controller; const PlayerSuperChatOverlay({required this.controller, Key? key}) : super(key: key); @override State createState() => _PlayerSuperChatOverlayState(); } class _PlayerSuperChatOverlayState extends State { final List _displayed = []; final Map _timers = {}; late Worker _worker; void _addSC(LiveSuperChatMessage sc, {int? customSeconds}) { if (_displayed.any((e) => e.sc == sc)) return; int showSeconds = customSeconds ?? 15; final expireAt = DateTime.now().add(Duration(seconds: showSeconds)); final localSC = LocalDisplaySC(sc, expireAt, showSeconds); _displayed.add(localSC); _timers[localSC] = Timer(Duration(seconds: showSeconds), () { setState(() { _displayed.remove(localSC); _timers.remove(localSC)?.cancel(); }); }); setState(() {}); } @override void initState() { super.initState(); // 首次进房时同步已有SC final now = DateTime.now().millisecondsSinceEpoch; for (var sc in widget.controller.superChats) { int remain = (sc.endTime.millisecondsSinceEpoch - now) ~/ 1000; if (remain > 0) { _addSC(sc, customSeconds: remain < 15 ? remain : 15); } } // 监听SC列表变化 _worker = ever>(widget.controller.superChats, (list) { // 新增 for (var sc in list) { if (!_displayed.any((e) => e.sc == sc)) { _addSC(sc); } } // 移除 _displayed.removeWhere((e) => !list.contains(e.sc)); setState(() {}); }); } @override void dispose() { _worker.dispose(); for (var t in _timers.values) { t.cancel(); } super.dispose(); } @override Widget build(BuildContext context) { final sorted = _displayed.toList() ..sort((a, b) => a.sc.endTime.compareTo(b.sc.endTime)); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ for (var localSC in sorted) Padding( padding: const EdgeInsets.only(bottom: 12), child: SizedBox( width: 240, child: PlayerSuperChatCard( message: localSC.sc, onExpire: () {}, duration: localSC.duration, ), ), ), ], ); } } ================================================ FILE: simple_live_app/lib/modules/mine/account/account_controller.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/douyin_account_service.dart'; import 'package:simple_live_core/simple_live_core.dart'; class AccountController extends GetxController { void bilibiliTap() async { if (BiliBiliAccountService.instance.logined.value) { var result = await Utils.showAlertDialog("确定要退出哔哩哔哩账号吗?", title: "退出登录"); if (result) { BiliBiliAccountService.instance.logout(); } } else { //AppNavigator.toBiliBiliLogin(); bilibiliLogin(); } } void bilibiliLogin() { Utils.showBottomSheet( title: "登录哔哩哔哩", child: Column( mainAxisSize: MainAxisSize.min, children: [ Visibility( visible: Platform.isAndroid || Platform.isIOS, child: ListTile( leading: const Icon(Icons.account_circle_outlined), title: const Text("Web登录"), subtitle: const Text("填写用户名密码登录"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); Get.toNamed(RoutePath.kBiliBiliWebLogin); }, ), ), ListTile( leading: const Icon(Icons.qr_code), title: const Text("扫码登录"), subtitle: const Text("使用哔哩哔哩APP扫描二维码登录"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); Get.toNamed(RoutePath.kBiliBiliQRLogin); }, ), ListTile( leading: const Icon(Icons.edit_outlined), title: const Text("Cookie登录"), subtitle: const Text("手动输入Cookie登录"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.back(); doBiliBiliCookieLogin(); }, ), ], ), ); } void doBiliBiliCookieLogin() async { var cookie = await Utils.showEditTextDialog( "", title: "请输入Cookie", hintText: "请输入Cookie", ); if (cookie == null || cookie.isEmpty) { return; } BiliBiliAccountService.instance.setCookie(cookie); await BiliBiliAccountService.instance.loadUserInfo(); } void douyinTap() async { if (DouyinAccountService.instance.hasCookie.value) { var result = await Utils.showAlertDialog("确定要清除自定义 ttwid 吗?", title: "清除配置"); if (result) { DouyinAccountService.instance.clearCookie(); SmartDialog.showToast("已清除自定义 ttwid,将使用默认 ttwid"); } } else { doDouyinCookieConfig(); } } void doDouyinCookieConfig() { // 初始化文本框时,只显示 ttwid 的值部分 var savedCookie = DouyinAccountService.instance.cookie; var displayText = savedCookie; if (savedCookie.startsWith('ttwid=')) { displayText = savedCookie.substring(6); // 去掉 "ttwid=" } var controller = TextEditingController(text: displayText); Get.dialog( AlertDialog( title: const Text("配置抖音 ttwid"), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "默认已内置有效的 ttwid,可观看所有画质(包括蓝光)。\n如有需要可自定义配置。", style: TextStyle(fontSize: 12, color: Colors.grey), ), const SizedBox(height: 12), TextField( controller: controller, maxLines: 3, decoration: const InputDecoration( hintText: "请粘贴 ttwid 值(留空则使用默认值)", border: OutlineInputBorder(), ), ), const SizedBox(height: 8), TextButton.icon( onPressed: () { // 提取 ttwid 的值部分(去掉 "ttwid=" 前缀) var defaultValue = DouyinSite.kDefaultCookie; if (defaultValue.startsWith('ttwid=')) { defaultValue = defaultValue.substring(6); // 去掉 "ttwid=" } controller.text = defaultValue; }, icon: const Icon(Icons.restore), label: const Text("恢复默认 ttwid"), ), ], ), ), actions: [ TextButton( onPressed: () => Get.back(), child: const Text("取消"), ), TextButton( onPressed: () { var input = controller.text.trim(); Get.back(); if (input.isEmpty) { DouyinAccountService.instance.clearCookie(); SmartDialog.showToast("已清除自定义 Cookie,将使用默认 ttwid"); } else { // 如果用户只输入了 ttwid 值,自动添加 "ttwid=" 前缀 var cookie = input; if (!input.startsWith('ttwid=')) { cookie = 'ttwid=$input'; } DouyinAccountService.instance.setCookie(cookie); SmartDialog.showToast("ttwid 已保存"); } }, child: const Text("确定"), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/mine/account/account_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/mine/account/account_controller.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/douyin_account_service.dart'; class AccountPage extends GetView { const AccountPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("账号管理"), ), body: ListView( children: [ const Padding( padding: AppStyle.edgeInsetsA12, child: Text( "哔哩哔哩账号需要登录才能看高清晰度的直播。", textAlign: TextAlign.center, ), ), Obx( () => ListTile( leading: Image.asset( 'assets/images/bilibili_2.png', width: 36, height: 36, ), title: const Text("哔哩哔哩"), subtitle: Text(BiliBiliAccountService.instance.name.value), trailing: BiliBiliAccountService.instance.logined.value ? const Icon(Icons.logout) : const Icon(Icons.chevron_right), onTap: controller.bilibiliTap, ), ), ListTile( leading: Image.asset( 'assets/images/douyu.png', width: 36, height: 36, ), title: const Text("斗鱼直播"), subtitle: const Text("无需登录"), enabled: false, trailing: const Icon(Icons.chevron_right), ), ListTile( leading: Image.asset( 'assets/images/huya.png', width: 36, height: 36, ), title: const Text("虎牙直播"), subtitle: const Text("无需登录"), enabled: false, trailing: const Icon(Icons.chevron_right), ), Obx( () => ListTile( leading: Image.asset( 'assets/images/douyin.png', width: 36, height: 36, ), title: const Text("抖音直播"), subtitle: Text(DouyinAccountService.instance.hasCookie.value ? "已自定义(${DouyinAccountService.instance.cookie.length} 字符)" : "使用默认 ttwid"), trailing: DouyinAccountService.instance.hasCookie.value ? const Icon(Icons.delete_outline) : const Icon(Icons.chevron_right), onTap: controller.douyinTap, ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/mine/account/bilibili/qr_login_controller.dart ================================================ import 'dart:async'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/requests/http_client.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; enum QRStatus { loading, unscanned, scanned, expired, failed, } class BiliBiliQRLoginController extends GetxController { @override void onInit() { loadQRCode(); super.onInit(); } Timer? timer; var qrcodeUrl = "".obs; var qrcodeKey = ""; /// 二维码状态 /// - [0] 加载中 /// - [1] 未扫描 /// - [2] 已扫描,待确认 /// - [3] 二维码已经失效 /// - [4] 登录失败 Rx qrStatus = QRStatus.loading.obs; void loadQRCode() async { try { qrStatus.value = QRStatus.loading; var result = await HttpClient.instance.getJson( "https://passport.bilibili.com/x/passport-login/web/qrcode/generate", ); if (result["code"] != 0) { throw result["message"]; } qrcodeKey = result["data"]["qrcode_key"]; qrcodeUrl.value = result["data"]["url"]; qrStatus.value = QRStatus.unscanned; startPoll(); } catch (e) { Log.logPrint(e); SmartDialog.showToast(e.toString()); qrStatus.value = QRStatus.failed; } } void startPoll() { timer = Timer.periodic( const Duration(seconds: 3), (timer) { pollQRStatus(); }, ); } void pollQRStatus() async { try { var response = await HttpClient.instance.get( "https://passport.bilibili.com/x/passport-login/web/qrcode/poll", queryParameters: { "qrcode_key": qrcodeKey, }, ); if (response.data["code"] != 0) { throw response.data["message"]; } var data = response.data["data"]; var code = data["code"]; if (code == 0) { var cookies = []; response.headers["set-cookie"]?.forEach((element) { var cookie = element.split(";")[0]; cookies.add(cookie); }); if (cookies.isNotEmpty) { var cookieStr = cookies.join(";"); Log.i(cookieStr); BiliBiliAccountService.instance.setCookie(cookieStr); await BiliBiliAccountService.instance.loadUserInfo(); Get.back(); } } else if (code == 86038) { qrStatus.value = QRStatus.expired; qrcodeKey = ""; timer?.cancel(); } else if (code == 86090) { qrStatus.value = QRStatus.scanned; } } catch (e) { Log.logPrint(e); SmartDialog.showToast(e.toString()); } } @override void onClose() { timer?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/mine/account/bilibili/qr_login_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/mine/account/bilibili/qr_login_controller.dart'; class BiliBiliQRLoginPage extends GetView { const BiliBiliQRLoginPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("哔哩哔哩账号登录")), body: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Obx( () { if (controller.qrStatus.value == QRStatus.loading) { return const CircularProgressIndicator(); } if (controller.qrStatus.value == QRStatus.failed) { return Column( mainAxisSize: MainAxisSize.min, children: [ const Text("二维码加载失败"), TextButton( onPressed: controller.loadQRCode, child: const Text("重试"), ), ], ); } if (controller.qrStatus.value == QRStatus.failed) { return Column( mainAxisSize: MainAxisSize.min, children: [ const Text("二维码已失效"), TextButton( onPressed: controller.loadQRCode, child: const Text("刷新二维码"), ), ], ); } return Column( children: [ ClipRRect( borderRadius: AppStyle.radius12, child: QrImageView( data: controller.qrcodeUrl.value, version: QrVersions.auto, backgroundColor: Colors.white, size: 200.0, padding: AppStyle.edgeInsetsA12, ), ), AppStyle.vGap8, Visibility( visible: controller.qrStatus.value == QRStatus.scanned, child: const Text("已扫描,请在手机上确认登录"), ), ], ); }, ), ), const Padding( padding: AppStyle.edgeInsetsA24, child: Text( "请使用哔哩哔哩手机客户端扫描二维码登录", textAlign: TextAlign.center, ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/mine/account/bilibili/web_login_controller.dart ================================================ import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; class BiliBiliWebLoginController extends BaseController { InAppWebViewController? webViewController; final CookieManager cookieManager = CookieManager.instance(); void onWebViewCreated(InAppWebViewController controller) { webViewController = controller; webViewController!.loadUrl( urlRequest: URLRequest( url: WebUri("https://passport.bilibili.com/login"), ), ); } void toQRLogin() async { await Get.toNamed(RoutePath.kBiliBiliQRLogin); Get.back(); } void onLoadStop(InAppWebViewController controller, Uri? uri) async { if (uri == null) { return; } if (uri.host == "m.bilibili.com") { logined(); } } Future logined() async { try { var cookies = await cookieManager.getCookies(url: WebUri("https://bilibili.com")); if (cookies.isEmpty) { return false; } var cookieStr = cookies.map((e) => "${e.name}=${e.value}").join(";"); Log.i(cookieStr); BiliBiliAccountService.instance.setCookie(cookieStr); await BiliBiliAccountService.instance.loadUserInfo(); Get.back(); return true; } catch (e) { return false; } } } ================================================ FILE: simple_live_app/lib/modules/mine/account/bilibili/web_login_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/modules/mine/account/bilibili/web_login_controller.dart'; class BiliBiliWebLoginPage extends GetView { const BiliBiliWebLoginPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("哔哩哔哩账号登录"), actions: [ TextButton.icon( onPressed: controller.toQRLogin, icon: const Icon(Icons.qr_code), label: const Text("二维码登录"), ), ], ), body: InAppWebView( onWebViewCreated: controller.onWebViewCreated, onLoadStop: controller.onLoadStop, initialSettings: InAppWebViewSettings( userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/118.0.0.0", useShouldOverrideUrlLoading: true, ), shouldOverrideUrlLoading: (webController, navigationAction) async { var uri = navigationAction.request.url; if (uri == null) { return NavigationActionPolicy.ALLOW; } if (uri.host == "m.bilibili.com" || uri.host == "www.bilibili.com") { await controller.logined(); return NavigationActionPolicy.CANCEL; } return NavigationActionPolicy.ALLOW; }, ), ); } } ================================================ FILE: simple_live_app/lib/modules/mine/history/history_controller.dart ================================================ import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:simple_live_app/services/db_service.dart'; class HistoryController extends BasePageController { @override Future> getData(int page, int pageSize) { if (page > 1) { return Future.value([]); } return Future.value(DBService.instance.getHistores()); } void clean() async { var result = await Utils.showAlertDialog("确定要清空观看记录吗?", title: "清空观看记录"); if (!result) { return; } await DBService.instance.historyBox.clear(); refreshData(); } void removeItem(History item) async { await DBService.instance.historyBox.delete(item.id); refreshData(); } } ================================================ FILE: simple_live_app/lib/modules/mine/history/history_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/mine/history/history_controller.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'package:simple_live_app/widgets/page_grid_view.dart'; class HistoryPage extends GetView { const HistoryPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { var rowCount = MediaQuery.of(context).size.width ~/ 500; if (rowCount < 1) rowCount = 1; return Scaffold( appBar: AppBar( title: const Text("观看记录"), actions: [ TextButton.icon( onPressed: controller.clean, icon: const Icon(Icons.delete_outline), label: const Text("清空"), ), ], ), body: PageGridView( crossAxisSpacing: 12, crossAxisCount: rowCount, pageController: controller, firstRefresh: true, itemBuilder: (_, i) { var item = controller.list[i]; var site = Sites.allSites[item.siteId]!; return Dismissible( key: ValueKey(item.id), direction: DismissDirection.endToStart, background: Container( color: Colors.red, padding: AppStyle.edgeInsetsA12, alignment: Alignment.centerRight, child: const Icon( Icons.delete, color: Colors.white, ), ), confirmDismiss: (direction) async { return await Utils.showAlertDialog("确定要删除此记录吗?", title: "删除记录"); }, onDismissed: (_) { controller.removeItem(item); }, child: ListTile( leading: NetImage( item.face, width: 48, height: 48, borderRadius: 24, ), title: Text(item.userName), subtitle: Row( children: [ Expanded( child: Row( children: [ Image.asset( site.logo, width: 20, ), AppStyle.hGap4, Text( site.name, style: const TextStyle( fontSize: 12, color: Colors.grey, ), ), ], ), ), Text( Utils.parseTime(item.updateTime), style: const TextStyle(fontSize: 12, color: Colors.grey), ), ], ), onTap: () { AppNavigator.toLiveRoomDetail(site: site, roomId: item.roomId); }, onLongPress: () async { var result = await Utils.showAlertDialog("确定要删除此记录吗?", title: "删除记录"); if (!result) { return; } controller.removeItem(item); }, ), ); }, ), ); } } ================================================ FILE: simple_live_app/lib/modules/mine/mine_page.dart ================================================ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/services/signalr_service.dart'; import 'package:url_launcher/url_launcher_string.dart'; class MinePage extends StatelessWidget { const MinePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return AnnotatedRegion( value: Get.isDarkMode ? SystemUiOverlayStyle.light.copyWith( systemNavigationBarColor: Colors.transparent, ) : SystemUiOverlayStyle.dark.copyWith( systemNavigationBarColor: Colors.transparent, ), child: SafeArea( child: ListView( padding: AppStyle.edgeInsetsA4, children: [ AppStyle.vGap12, ListTile( leading: Image.asset( 'assets/images/logo.png', width: 56, height: 56, ), title: const Text( "Simple Live", style: TextStyle(height: 1.0), ), subtitle: const Text("简简单单看直播"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.dialog(AboutDialog( applicationIcon: Image.asset( 'assets/images/logo.png', width: 48, height: 48, ), applicationName: "Simple Live", applicationVersion: "简简单单看直播", applicationLegalese: "Ver ${Utils.packageInfo.version}", )); }, ), Divider( indent: 12, endIndent: 12, color: Colors.grey.withAlpha(25), ), _buildCard( context, children: [ ListTile( leading: const Icon(Remix.history_line), title: const Text("观看记录"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kHistory); }, ), ], ), Divider( indent: 12, endIndent: 12, color: Colors.grey.withAlpha(25), ), ListTile( leading: const Icon(Remix.account_circle_line), title: const Text("账号管理"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsAccount); }, ), Divider( indent: 12, endIndent: 12, color: Colors.grey.withAlpha(25), ), ListTile( leading: const Icon(Icons.devices), title: const Text("数据同步"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSync); }, ), Divider( indent: 12, endIndent: 12, color: Colors.grey.withAlpha(25), ), ListTile( leading: const Icon(Remix.link), title: const Text("链接解析"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kTools); }, ), Divider( indent: 12, endIndent: 12, color: Colors.grey.withAlpha(25), ), _buildCard( context, children: [ ListTile( leading: const Icon(Remix.moon_line), title: const Text("外观设置"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kAppstyleSetting); }, ), ListTile( leading: const Icon(Remix.home_2_line), title: const Text("主页设置"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsIndexed); }, ), ListTile( leading: const Icon(Remix.play_circle_line), title: const Text("直播设置"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsPlay); }, ), ListTile( leading: const Icon(Remix.text), title: const Text("弹幕设置"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsDanmu); }, ), ListTile( leading: const Icon(Remix.heart_line), title: const Text("关注设置"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsFollow); }, ), ListTile( leading: const Icon(Remix.timer_2_line), title: const Text("定时关闭"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsAutoExit); }, ), ListTile( leading: const Icon(Remix.apps_line), title: const Text("其他设置"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { Get.toNamed(RoutePath.kSettingsOther); }, ), if (kDebugMode) ListTile( leading: const Icon(Remix.apps_line), title: const Text("测试"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () async { SignalRService signalRService = SignalRService(); await signalRService.connect(); //Get.toNamed(RoutePath.kTest); var room = await signalRService.createRoom(); Log.logPrint(room); }, ), ], ), Divider( indent: 12, endIndent: 12, color: Colors.grey.withAlpha(25), ), _buildCard( context, children: [ const ListTile( leading: Icon(Remix.error_warning_line), title: Text("免责声明"), trailing: Icon( Icons.chevron_right, color: Colors.grey, ), onTap: Utils.showStatement, ), ListTile( leading: const Icon(Remix.github_line), title: const Text("开源主页"), trailing: const Icon( Icons.chevron_right, color: Colors.grey, ), onTap: () { launchUrlString( "https://github.com/xiaoyaocz/dart_simple_live", mode: LaunchMode.externalApplication, ); }, ), ], ), ], ), ), ); } Widget _buildCard(BuildContext context, {required List children}) { return Theme( data: Theme.of(context).copyWith( listTileTheme: ListTileThemeData( shape: RoundedRectangleBorder(borderRadius: AppStyle.radius8), ), ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: children, ), ); } } ================================================ FILE: simple_live_app/lib/modules/mine/parse/parse_controller.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; class ParseController extends GetxController { final TextEditingController roomJumpToController = TextEditingController(); final TextEditingController getUrlController = TextEditingController(); void jumpToRoom(String e) async { if (e.isEmpty) { SmartDialog.showToast("链接不能为空"); return; } // 隐藏键盘 FocusManager.instance.primaryFocus?.unfocus(); var parseResult = await parse(e); if (parseResult.isEmpty && parseResult.first == "") { SmartDialog.showToast("无法解析此链接"); return; } // 延迟200ms跳转,等待键盘隐藏 Future.delayed(const Duration(milliseconds: 200), () { Site site = parseResult[1]; AppNavigator.toLiveRoomDetail(site: site, roomId: parseResult.first); }); } void getPlayUrl(String e) async { if (e.isEmpty) { SmartDialog.showToast("链接不能为空"); return; } var parseResult = await parse(e); if (parseResult.isEmpty && parseResult.first == "") { SmartDialog.showToast("无法解析此链接"); return; } Site site = parseResult[1]; try { SmartDialog.showLoading(msg: ""); var detail = await site.liveSite.getRoomDetail(roomId: parseResult.first); var qualites = await site.liveSite.getPlayQualites(detail: detail); SmartDialog.dismiss(status: SmartStatus.loading); if (qualites.isEmpty) { SmartDialog.showToast("读取直链失败,无法读取清晰度"); return; } var result = await Get.dialog(SimpleDialog( title: const Text("选择清晰度"), children: qualites .map( (e) => ListTile( title: Text( e.quality, textAlign: TextAlign.center, ), onTap: () { Get.back(result: e); }, ), ) .toList(), )); if (result == null) { return; } SmartDialog.showLoading(msg: ""); var playUrl = await site.liveSite.getPlayUrls(detail: detail, quality: result); SmartDialog.dismiss(status: SmartStatus.loading); await Get.dialog(SimpleDialog( title: const Text("选择线路"), children: playUrl.urls .map( (e) => ListTile( title: Text( "线路${playUrl.urls.indexOf(e) + 1}", ), subtitle: Text( e, maxLines: 1, overflow: TextOverflow.ellipsis, ), onTap: () { Clipboard.setData(ClipboardData(text: e)); Get.back(); SmartDialog.showToast("已复制直链"); }, ), ) .toList(), )); } catch (e) { SmartDialog.showToast("读取直链失败"); } finally { SmartDialog.dismiss(status: SmartStatus.loading); } } Future parse(String url) async { var id = ""; if (url.contains("bilibili.com")) { var regExp = RegExp(r"bilibili\.com/([\d|\w]+)"); id = regExp.firstMatch(url)?.group(1) ?? ""; return [id, Sites.allSites[Constant.kBiliBili]!]; } if (url.contains("b23.tv")) { var btvReg = RegExp(r"https?:\/\/b23.tv\/[0-9a-z-A-Z]+"); var u = btvReg.firstMatch(url)?.group(0) ?? ""; var location = await getLocation(u); return await parse(location); } if (url.contains("douyu.com")) { var regExp = RegExp(r"douyu\.com/([\d|\w]+)"); // 适配 topic_url if(url.contains("topic")){ regExp = RegExp(r"[?&]rid=([\d]+)"); } id = regExp.firstMatch(url)?.group(1) ?? ""; return [id, Sites.allSites[Constant.kDouyu]!]; } if (url.contains("huya.com")) { var regExp = RegExp(r"huya\.com/([\d|\w]+)"); id = regExp.firstMatch(url)?.group(1) ?? ""; return [id, Sites.allSites[Constant.kHuya]!]; } if (url.contains("live.douyin.com")) { var regExp = RegExp(r"live\.douyin\.com/([\d|\w]+)"); id = regExp.firstMatch(url)?.group(1) ?? ""; return [id, Sites.allSites[Constant.kDouyin]!]; } if (url.contains("webcast.amemv.com")) { var regExp = RegExp(r"reflow/(\d+)"); id = regExp.firstMatch(url)?.group(1) ?? ""; return [id, Sites.allSites[Constant.kDouyin]!]; } if (url.contains("v.douyin.com")) { var regExp = RegExp(r"http.?://v.douyin.com/[\d\w]+/"); var u = regExp.firstMatch(url)?.group(0) ?? ""; var location = await getLocation(u); return await parse(location); } return []; } Future getLocation(String url) async { try { if (url.isEmpty) return ""; await Dio().get( url, options: Options( followRedirects: false, ), ); } on DioException catch (e) { if (e.response!.statusCode == 302) { var redirectUrl = e.response!.headers.value("Location"); if (redirectUrl != null) { return redirectUrl; } } } catch (e) { Log.logPrint(e); } return ""; } } ================================================ FILE: simple_live_app/lib/modules/mine/parse/parse_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/mine/parse/parse_controller.dart'; class ParsePage extends GetView { const ParsePage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("链接解析"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ buildCard( context: context, child: ExpansionTile( title: const Text("直播间跳转"), childrenPadding: AppStyle.edgeInsetsH12, initiallyExpanded: true, children: [ TextField( minLines: 3, maxLines: 3, controller: controller.roomJumpToController, textInputAction: TextInputAction.go, decoration: InputDecoration( border: const OutlineInputBorder(), hintText: "输入或粘贴哔哩哔哩直播/虎牙直播/斗鱼直播/抖音直播的链接", contentPadding: AppStyle.edgeInsetsA12, enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.grey.withAlpha(50), ), ), ), onSubmitted: controller.jumpToRoom, ), Container( margin: AppStyle.edgeInsetsB4, width: double.infinity, child: TextButton.icon( onPressed: () { controller .jumpToRoom(controller.roomJumpToController.text); }, icon: const Icon(Remix.play_circle_line), label: const Text("链接跳转"), ), ), ], ), ), buildCard( context: context, child: ExpansionTile( title: const Text("获取直链"), childrenPadding: AppStyle.edgeInsetsH12, initiallyExpanded: true, children: [ TextField( minLines: 3, maxLines: 3, controller: controller.getUrlController, textInputAction: TextInputAction.go, decoration: InputDecoration( border: const OutlineInputBorder(), hintText: "输入或粘贴哔哩哔哩直播/虎牙直播/斗鱼直播/抖音直播的链接", contentPadding: AppStyle.edgeInsetsA12, enabledBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.grey.withAlpha(50), ), ), ), onSubmitted: controller.getPlayUrl, ), Container( margin: AppStyle.edgeInsetsB4, width: double.infinity, child: TextButton.icon( onPressed: () { controller.getPlayUrl(controller.getUrlController.text); }, icon: const Icon(Remix.link), label: const Text("获取直链"), ), ), ], ), ), const Padding( padding: AppStyle.edgeInsetsV12, child: SelectableText('''支持以下类型的链接解析: 哔哩哔哩: https://live.bilibili.com/xxxxx https://b23.tv/xxxxx 虎牙直播: https://www.huya.com/xxxxx 斗鱼直播: https://www.douyu.com/xxxxx https://www.douyu.com/topic/xxx?rid=xxx 抖音直播: https://v.douyin.com/xxxxx https://live.douyin.com/xxxxx https://webcast.amemv.com/webcast/reflow/xxxxx ''', style: TextStyle(color: Colors.grey)), ), ], ), ); } Widget buildCard({required BuildContext context, required Widget child}) { return Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: AppStyle.radius8, boxShadow: Get.isDarkMode ? [] : [ BoxShadow( blurRadius: 8, color: Colors.grey.withAlpha(50), ) ], ), margin: AppStyle.edgeInsetsB12, child: Theme( data: Theme.of(context).copyWith( dividerColor: Colors.transparent, ), child: child, ), ); } } ================================================ FILE: simple_live_app/lib/modules/other/debug_log_page.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/log.dart'; class DebugLogPage extends StatelessWidget { const DebugLogPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Log"), actions: [ IconButton( onPressed: () async { var msg = Log.debugLogs .map((x) => "${x.datetime}\r\n${x.content}") .join('\r\n\r\n'); var dir = await getApplicationDocumentsDirectory(); var logFile = File( '${dir.path}/${DateTime.now().millisecondsSinceEpoch}.log'); await logFile.writeAsString(msg); SharePlus.instance.share(ShareParams( files: [XFile(logFile.path)], )); }, icon: const Icon(Icons.save), ), IconButton( onPressed: () { Log.debugLogs.clear(); }, icon: const Icon(Icons.clear_all), ), ], ), body: Obx( () => ListView.separated( itemCount: Log.debugLogs.length, separatorBuilder: (_, i) => const Divider(), padding: AppStyle.edgeInsetsA12, itemBuilder: (_, i) { var item = Log.debugLogs[i]; return SelectableText( "${item.datetime.toString()}\r\n${item.content}", style: TextStyle( color: item.color, fontSize: 12, ), ); }, ), ), ); } } ================================================ FILE: simple_live_app/lib/modules/search/douyin/douyin_search_controller.dart ================================================ import 'dart:io'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:url_launcher/url_launcher_string.dart'; class DouyinSearchController extends BaseController { InAppWebViewController? webViewController; void onWebViewCreated(InAppWebViewController controller) { webViewController = controller; } RxList list = [].obs; String keyword = ""; /// 搜索模式,0=直播间,1=主播 var searchMode = 0.obs; final Site site; DouyinSearchController( this.site, ); var searchUrl = "https://www.douyin.com/search/dnf?type=live"; void reloadWebView() { if (keyword.isEmpty) { return; } searchUrl = "https://www.douyin.com/search/${Uri.encodeComponent(keyword)}?type=live"; if (Platform.isAndroid || Platform.isIOS) { webViewController!.loadUrl( urlRequest: URLRequest( url: WebUri(searchUrl), ), ); } } void onLoadStop(InAppWebViewController controller, Uri? uri) async { pageLoadding.value = false; } void onLoadStart(InAppWebViewController controller, Uri? uri) async { pageLoadding.value = true; } Future onCreateWindow(InAppWebViewController controller, CreateWindowAction createWindowAction) async { if (createWindowAction.request.url?.host == "live.douyin.com") { { var regExp = RegExp(r"live\.douyin\.com/([\d|\w]+)"); var id = regExp .firstMatch(createWindowAction.request.url.toString()) ?.group(1) ?? ""; AppNavigator.toLiveRoomDetail(site: site, roomId: id); return false; } } return false; } void openBrowser() { launchUrlString(searchUrl); Get.offAndToNamed(RoutePath.kTools); } } ================================================ FILE: simple_live_app/lib/modules/search/douyin/douyin_search_view.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/search/douyin/douyin_search_controller.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/widgets/keep_alive_wrapper.dart'; import 'package:simple_live_app/widgets/status/app_loadding_widget.dart'; class DouyinSearchView extends StatelessWidget { const DouyinSearchView({Key? key}) : super(key: key); DouyinSearchController get controller => Get.find(); @override Widget build(BuildContext context) { var roomRowCount = MediaQuery.of(context).size.width ~/ 200; if (roomRowCount < 2) roomRowCount = 2; var userRowCount = MediaQuery.of(context).size.width ~/ 500; if (userRowCount < 1) userRowCount = 1; return KeepAliveWrapper( child: Stack( children: [ SizedBox( width: double.infinity, height: double.infinity, child: Center( child: Padding( padding: AppStyle.edgeInsetsA12, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ const Text( "暂不支持抖音搜索,请打开浏览器搜索,然后复制直播间链接进行解析", textAlign: TextAlign.center, ), TextButton.icon( onPressed: controller.openBrowser, icon: const Icon(Icons.open_in_browser), label: const Text("打开浏览器"), ), ], ), ), ), ), if (Platform.isAndroid || Platform.isIOS) InAppWebView( onWebViewCreated: controller.onWebViewCreated, onLoadStop: controller.onLoadStop, onLoadStart: controller.onLoadStart, initialSettings: InAppWebViewSettings( useOnLoadResource: true, userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/118.0.0.0", useShouldOverrideUrlLoading: true, ), onCreateWindow: controller.onCreateWindow, shouldOverrideUrlLoading: (webController, navigationAction) async { var uri = navigationAction.request.url; if (uri == null) { return NavigationActionPolicy.ALLOW; } if (uri.host == "live.douyin.com") { var regExp = RegExp(r"live\.douyin\.com/([\d|\w]+)"); var id = regExp.firstMatch(uri.toString())?.group(1) ?? ""; AppNavigator.toLiveRoomDetail( site: controller.site, roomId: id); return NavigationActionPolicy.CANCEL; } return NavigationActionPolicy.ALLOW; }, ), Obx( () => Visibility( visible: controller.pageLoadding.value, child: const AppLoaddingWidget(), ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/search/search_controller.dart ================================================ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/search/search_list_controller.dart'; class AppSearchController extends GetxController with GetSingleTickerProviderStateMixin { late TabController tabController; int index = 0; var searchMode = 0.obs; AppSearchController() { tabController = TabController(length: Sites.supportSites.length, vsync: this); tabController.animation?.addListener(() { var currentIndex = (tabController.animation?.value ?? 0).round(); if (index == currentIndex) { return; } index = currentIndex; // if (Sites.supportSites[index].id == Constant.kDouyin) { // return; // } var controller = Get.find(tag: Sites.supportSites[index].id); if (controller.list.isEmpty && !controller.pageEmpty.value && controller.keyword.isNotEmpty) { controller.refreshData(); } }); } StreamSubscription? streamSubscription; TextEditingController searchController = TextEditingController(); @override void onInit() { for (var site in Sites.supportSites) { // if (site.id == Constant.kDouyin) { // Get.put(DouyinSearchController(site)); // } else { Get.put( SearchListController(site), tag: site.id, ); //} } super.onInit(); } void doSearch() { if (searchController.text.isEmpty) { return; } for (var site in Sites.supportSites) { // if (site.id == Constant.kDouyin) { // var controller = Get.find(); // controller.keyword = searchController.text; // controller.searchMode.value = searchMode.value; // controller.reloadWebView(); // } else { var controller = Get.find(tag: site.id); controller.clear(); controller.keyword = searchController.text; controller.searchMode.value = searchMode.value; //} } // if (Sites.supportSites[index].id != Constant.kDouyin) { var controller = Get.find(tag: Sites.supportSites[index].id); controller.refreshData(); //} } @override void onClose() { streamSubscription?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/search/search_list_controller.dart ================================================ import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/sites.dart'; class SearchListController extends BasePageController { String keyword = ""; /// 搜索模式,0=直播间,1=主播 var searchMode = 0.obs; final Site site; SearchListController( this.site, ); @override Future refreshData() async { if (keyword.isEmpty) { return; } return await super.refreshData(); } @override Future getData(int page, int pageSize) async { if (keyword.isEmpty) { return []; } if (searchMode.value == 1) { // 搜索主播 var result = await site.liveSite.searchAnchors(keyword, page: page); return result.items; } var result = await site.liveSite.searchRooms(keyword, page: page); return result.items; } void clear() { pageEmpty.value = false; list.clear(); } } ================================================ FILE: simple_live_app/lib/modules/search/search_list_view.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/search/search_list_controller.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/widgets/keep_alive_wrapper.dart'; import 'package:simple_live_app/widgets/live_room_card.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'package:simple_live_app/widgets/page_grid_view.dart'; import 'package:simple_live_core/simple_live_core.dart'; class SearchListView extends StatelessWidget { final String tag; const SearchListView(this.tag, {Key? key}) : super(key: key); SearchListController get controller => Get.find(tag: tag); @override Widget build(BuildContext context) { var roomRowCount = MediaQuery.of(context).size.width ~/ 200; if (roomRowCount < 2) roomRowCount = 2; var userRowCount = MediaQuery.of(context).size.width ~/ 500; if (userRowCount < 1) userRowCount = 1; return KeepAliveWrapper( child: Obx( () => controller.searchMode.value == 0 ? PageGridView( pageController: controller, padding: AppStyle.edgeInsetsA12, firstRefresh: false, mainAxisSpacing: 12, crossAxisSpacing: 12, crossAxisCount: roomRowCount, showPageLoadding: true, itemBuilder: (_, i) { var item = controller.list[i] as LiveRoomItem; return LiveRoomCard(controller.site, item); }, ) : PageGridView( crossAxisSpacing: 12, crossAxisCount: userRowCount, pageController: controller, firstRefresh: true, itemBuilder: (_, i) { var item = controller.list[i] as LiveAnchorItem; return ListTile( leading: NetImage( item.avatar, width: 48, height: 48, borderRadius: 24, ), title: Text(item.userName), subtitle: Row( mainAxisSize: MainAxisSize.min, children: [ Container( width: 8, height: 8, decoration: BoxDecoration( color: item.liveStatus ? Colors.green : Colors.grey, borderRadius: AppStyle.radius12, ), ), AppStyle.hGap4, Text( item.liveStatus ? "直播中" : "未开播", style: TextStyle( fontSize: 12, fontWeight: FontWeight.normal, color: item.liveStatus ? null : Colors.grey, ), ), ], ), onTap: () { AppNavigator.toLiveRoomDetail( site: controller.site, roomId: item.roomId); }, ); }, ), ), ); } } ================================================ FILE: simple_live_app/lib/modules/search/search_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/search/search_controller.dart'; import 'package:simple_live_app/modules/search/search_list_view.dart'; class SearchPage extends GetView { const SearchPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, title: TextField( controller: controller.searchController, autofocus: true, decoration: InputDecoration( hintText: "搜点什么吧", border: OutlineInputBorder( borderRadius: AppStyle.radius24, ), contentPadding: AppStyle.edgeInsetsH12, prefixIcon: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( onPressed: Get.back, icon: const Icon(Icons.arrow_back), ), Obx( () => DropdownButton( underline: const SizedBox(), items: const [ DropdownMenuItem( value: 0, child: Text("房间"), ), DropdownMenuItem( value: 1, child: Text("主播"), ), ], value: controller.searchMode.value, onChanged: (e) { controller.searchMode.value = e ?? 0; controller.doSearch(); }, ), ), AppStyle.hGap8, ], ), suffixIcon: IconButton( onPressed: controller.doSearch, icon: const Icon(Icons.search), ), ), onSubmitted: (e) { controller.doSearch(); }, ), bottom: TabBar( controller: controller.tabController, padding: EdgeInsets.zero, tabAlignment: TabAlignment.center, tabs: Sites.supportSites .map( (e) => Tab( //text: e.name, child: Row( children: [ Image.asset( e.logo, width: 24, ), AppStyle.hGap8, Text(e.name), ], ), ), ) .toList(), labelPadding: AppStyle.edgeInsetsH20, isScrollable: true, indicatorSize: TabBarIndicatorSize.label, ), ), body: TabBarView( physics: const NeverScrollableScrollPhysics(), controller: controller.tabController, children: Sites.supportSites .map((e) => SearchListView( e.id, ) // (e) => e.id == Constant.kDouyin // ? const DouyinSearchView() // : SearchListView( // e.id, // ), ) .toList(), ), ); } } ================================================ FILE: simple_live_app/lib/modules/settings/appstyle_setting_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; class AppstyleSettingPage extends GetView { const AppstyleSettingPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("外观设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Text( "显示主题", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Obx( () => RadioGroup( groupValue: controller.themeMode.value, onChanged: (e) { controller.setTheme(e ?? 0); }, child: const Column( mainAxisSize: MainAxisSize.min, children: [ RadioListTile( title: Text( "跟随系统", ), visualDensity: VisualDensity.compact, value: 0, contentPadding: AppStyle.edgeInsetsH12, ), RadioListTile( title: Text( "浅色模式", ), visualDensity: VisualDensity.compact, value: 1, contentPadding: AppStyle.edgeInsetsH12, ), RadioListTile( title: Text( "深色模式", ), visualDensity: VisualDensity.compact, value: 2, contentPadding: AppStyle.edgeInsetsH12, ), ], ), ), ), ), AppStyle.vGap12, Padding( padding: AppStyle.edgeInsetsA12, child: Text( "主题颜色", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Obx( () => Column( mainAxisSize: MainAxisSize.min, children: [ SettingsSwitch( value: controller.isDynamic.value, title: "动态取色", onChanged: (e) { controller.setIsDynamic(e); Get.forceAppUpdate(); }, ), if (!controller.isDynamic.value) AppStyle.divider, if (!controller.isDynamic.value) Padding( padding: AppStyle.edgeInsetsA12, child: Wrap( spacing: 8, runSpacing: 8, children: [ const Color(0xffEF5350), const Color(0xff3498db), const Color(0xffF06292), const Color(0xff9575CD), const Color(0xff26C6DA), const Color(0xff26A69A), const Color(0xffFFF176), const Color(0xffFF9800), ] .map( (e) => GestureDetector( onTap: () { controller.setStyleColor(e.toARGB32()); Get.forceAppUpdate(); }, child: Container( width: 36, height: 36, decoration: BoxDecoration( color: e, borderRadius: AppStyle.radius4, border: Border.all( color: Colors.grey.withAlpha(50), width: 1, ), ), child: Obx( () => Center( child: Icon( Icons.check, color: controller.styleColor.value == e.toARGB32() ? Colors.white : Colors.transparent, ), ), ), ), ), ) .toList(), ), ), ], ), ), ), ], ), ); } } // extension ColorExt on Color { // static int _floatToInt8(double x) { // return (x * 255.0).round() & 0xff; // } // int get v => // _floatToInt8(a) << 24 | // _floatToInt8(r) << 16 | // _floatToInt8(g) << 8 | // _floatToInt8(b) << 0; // } ================================================ FILE: simple_live_app/lib/modules/settings/auto_exit_settings_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/widgets/settings/settings_action.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; class AutoExitSettingsPage extends GetView { const AutoExitSettingsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("定时关闭设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ SettingsCard( child: Column( children: [ Obx( () => SettingsSwitch( value: controller.autoExitEnable.value, title: "启用定时关闭", onChanged: (e) { controller.setAutoExitEnable(e); }, ), ), Obx( () => Visibility( visible: controller.autoExitEnable.value, child: AppStyle.divider, ), ), Obx( () => Visibility( visible: controller.autoExitEnable.value, child: SettingsAction( title: "自动关闭时间", value: "${controller.autoExitDuration.value ~/ 60}小时${controller.autoExitDuration.value % 60}分钟", subtitle: "从进入直播间开始倒计时", onTap: () { setTimer(context); }, ), ), ), ], ), ), ], ), ); } void setTimer(BuildContext context) async { var value = await showTimePicker( context: context, initialTime: TimeOfDay( hour: controller.autoExitDuration.value ~/ 60, minute: controller.autoExitDuration.value % 60, ), initialEntryMode: TimePickerEntryMode.inputOnly, builder: (_, child) { return MediaQuery( data: MediaQuery.of(context).copyWith( alwaysUse24HourFormat: true, ), child: child!, ); }, ); if (value == null || (value.hour == 0 && value.minute == 0)) { return; } var duration = Duration(hours: value.hour, minutes: value.minute); controller.setAutoExitDuration(duration.inMinutes); } } ================================================ FILE: simple_live_app/lib/modules/settings/danmu_settings_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/widgets/settings/settings_action.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_number.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; class DanmuSettingsPage extends StatelessWidget { const DanmuSettingsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("弹幕设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: const [ DanmuSettingsView(), ], ), ); } } class DanmuSettingsView extends GetView { final Function()? onTapDanmuShield; final DanmakuController? danmakuController; const DanmuSettingsView({ this.onTapDanmuShield, this.danmakuController, super.key, }); @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Text( "弹幕屏蔽", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ SettingsAction( title: "关键词屏蔽", onTap: onTapDanmuShield ?? () => Get.toNamed(RoutePath.kSettingsDanmuShield), ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "弹幕设置", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ Obx( () => SettingsSwitch( title: "默认开关", value: controller.danmuEnable.value, onChanged: (e) { controller.setDanmuEnable(e); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "显示区域", value: (controller.danmuArea.value * 100).toInt(), min: 10, max: 100, step: 10, unit: "%", onChanged: (e) { controller.setDanmuArea(e / 100.0); updateDanmuOption( danmakuController?.option.copyWith(area: e / 100.0), ); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "不透明度", value: (controller.danmuOpacity.value * 100).toInt(), min: 10, max: 100, step: 10, unit: "%", onChanged: (e) { controller.setDanmuOpacity(e / 100.0); updateDanmuOption( danmakuController?.option.copyWith(opacity: e / 100.0), ); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "字体大小", value: controller.danmuSize.toInt(), min: 8, max: 48, onChanged: (e) { controller.setDanmuSize(e.toDouble()); updateDanmuOption( danmakuController?.option .copyWith(fontSize: e.toDouble()), ); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "字体粗细", value: controller.danmuFontWeight.value, min: 1, max: 9, step: 1, displayValue: [ "极细", "很细", "细", "正常", "小粗", "偏粗", "粗", "很粗", "极粗" ][controller.danmuFontWeight.value - 1] .toString(), onChanged: (e) { controller.setDanmuFontWeight(e); updateDanmuOption( danmakuController?.option.copyWith( fontWeight: e, ), ); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "滚动速度", subtitle: "弹幕持续时间(秒),越小速度越快", value: controller.danmuSpeed.toInt(), min: 4, max: 20, onChanged: (e) { controller.setDanmuSpeed(e.toDouble()); updateDanmuOption( danmakuController?.option.copyWith(duration: e.toInt()), ); }, ), ), // AppStyle.divider, // Obx( // () => SettingsNumber( // title: "字体描边", // value: controller.danmuStrokeWidth.toInt(), // min: 0, // max: 10, // onChanged: (e) { // controller.setDanmuStrokeWidth(e.toDouble()); // updateDanmuOption( // danmakuController?.option // .copyWith(strokeWidth: e.toDouble()), // ); // }, // ), // ), AppStyle.divider, Obx( () => SettingsNumber( title: "顶部边距", subtitle: "曲面屏显示不全可设置此选项", value: controller.danmuTopMargin.toInt(), min: 0, max: 48, step: 4, onChanged: (e) { controller.setDanmuTopMargin(e.toDouble()); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "底部边距", subtitle: "曲面屏显示不全可设置此选项", value: controller.danmuBottomMargin.toInt(), min: 0, max: 48, step: 4, onChanged: (e) { controller.setDanmuBottomMargin(e.toDouble()); }, ), ), ], ), ), ], ); } void updateDanmuOption(DanmakuOption? option) { if (danmakuController == null || option == null) return; danmakuController!.updateOption(option); } } ================================================ FILE: simple_live_app/lib/modules/settings/danmu_shield/danmu_shield_controller.dart ================================================ import 'package:flutter/widgets.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; class DanmuShieldController extends BaseController { final TextEditingController textEditingController = TextEditingController(); final AppSettingsController settingsController = Get.find(); void add() { if (textEditingController.text.isEmpty) { SmartDialog.showToast("请输入关键词"); return; } settingsController.addShieldList(textEditingController.text.trim()); textEditingController.text = ""; } void remove(String item) { settingsController.removeShieldList(item); } } ================================================ FILE: simple_live_app/lib/modules/settings/danmu_shield/danmu_shield_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/settings/danmu_shield/danmu_shield_controller.dart'; class DanmuShieldPage extends GetView { const DanmuShieldPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("弹幕屏蔽"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ TextField( controller: controller.textEditingController, decoration: InputDecoration( contentPadding: AppStyle.edgeInsetsH12, border: const OutlineInputBorder(), hintText: "请输入关键词或正则表达式", suffixIcon: TextButton.icon( onPressed: controller.add, icon: const Icon(Icons.add), label: const Text("添加"), ), ), onSubmitted: (e) { controller.add(); }, ), AppStyle.vGap4, Text( '以"/"开头和结尾将视作正则表达式, 如"/\\d+/"表示屏蔽所有数字', style: Get.textTheme.bodySmall, ), AppStyle.vGap12, Obx( () => Text( "已添加${controller.settingsController.shieldList.length}个关键词(点击移除)", style: Get.textTheme.titleSmall, ), ), AppStyle.vGap12, Obx( () => Wrap( runSpacing: 12, spacing: 12, children: controller.settingsController.shieldList .map( (item) => InkWell( borderRadius: AppStyle.radius24, onTap: () { controller.remove(item); }, child: Container( decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: AppStyle.radius24, ), padding: AppStyle.edgeInsetsH12.copyWith( top: 4, bottom: 4, ), child: Text( item, style: Get.textTheme.bodyMedium, ), ), ), ) .toList(), ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/settings/follow_settings_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/services/follow_service.dart'; import 'package:simple_live_app/widgets/settings/settings_action.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; import 'dart:io'; class FollowSettingsPage extends GetView { const FollowSettingsPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("关注设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ SettingsCard( child: Column( children: [ Obx( () => SettingsSwitch( value: controller.autoUpdateFollowEnable.value, title: "自动更新关注直播状态", onChanged: (e) { controller.setAutoUpdateFollowEnable(e); FollowService.instance.initTimer(); }, ), ), Obx( () => Visibility( visible: controller.autoUpdateFollowEnable.value, child: AppStyle.divider, ), ), Obx( () => Visibility( visible: controller.autoUpdateFollowEnable.value, child: SettingsAction( title: "自动更新间隔", value: "${controller.autoUpdateFollowDuration.value ~/ 60}小时${controller.autoUpdateFollowDuration.value % 60}分钟", onTap: () { setTimer(context); }, ), ), ), AppStyle.divider, Obx( () { var threadCount = controller.updateFollowThreadCount.value; var displayValue = threadCount == 0 ? "自动 (根据 CPU 核心数)" : "$threadCount"; return SettingsAction( title: "更新并发数", subtitle: "0 = 自动根据 CPU 核心数优化(推荐),或手动设置 1-20", value: displayValue, onTap: () { showConcurrencyDialog(); }, ); }, ), ], ), ), ], ), ); } void setTimer(BuildContext context) async { var value = await showTimePicker( context: context, initialTime: TimeOfDay( hour: controller.autoUpdateFollowDuration.value ~/ 60, minute: controller.autoUpdateFollowDuration.value % 60, ), initialEntryMode: TimePickerEntryMode.inputOnly, builder: (_, child) { return MediaQuery( data: MediaQuery.of(context).copyWith( alwaysUse24HourFormat: true, ), child: child!, ); }, ); if (value == null || (value.hour == 0 && value.minute == 0)) { return; } var duration = Duration(hours: value.hour, minutes: value.minute); controller.setAutoUpdateFollowDuration(duration.inMinutes); FollowService.instance.initTimer(); } void showConcurrencyDialog() { var currentValue = controller.updateFollowThreadCount.value; var cpuCount = Platform.numberOfProcessors; var autoValue = (cpuCount * 2.5).round().clamp(4, 20); Get.dialog( AlertDialog( title: const Text("设置更新并发数"), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "CPU 核心数: $cpuCount", style: const TextStyle(fontSize: 12, color: Colors.grey), ), Text( "自动推荐值: $autoValue", style: const TextStyle(fontSize: 12, color: Colors.grey), ), const SizedBox(height: 16), const Text( "选择并发数:", style: TextStyle(fontSize: 14), ), const SizedBox(height: 8), // 快捷选项 Wrap( spacing: 8, runSpacing: 8, children: [ _buildQuickOption(0, "自动 ($autoValue)", currentValue), _buildQuickOption(4, "4", currentValue), _buildQuickOption(8, "8", currentValue), _buildQuickOption(12, "12", currentValue), _buildQuickOption(16, "16", currentValue), _buildQuickOption(20, "20", currentValue), ], ), const SizedBox(height: 16), // 自定义输入 TextField( keyboardType: TextInputType.number, decoration: const InputDecoration( labelText: "自定义 (1-20)", border: OutlineInputBorder(), hintText: "输入 1-20 之间的数字", ), onSubmitted: (value) { var num = int.tryParse(value); if (num != null && num >= 0 && num <= 20) { controller.setUpdateFollowThreadCount(num); Get.back(); } }, ), ], ), actions: [ TextButton( onPressed: () => Get.back(), child: const Text("取消"), ), ], ), ); } Widget _buildQuickOption(int value, String label, int currentValue) { var isSelected = currentValue == value; return ChoiceChip( label: Text(label), selected: isSelected, onSelected: (selected) { if (selected) { controller.setUpdateFollowThreadCount(value); Get.back(); } }, ); } } ================================================ FILE: simple_live_app/lib/modules/settings/indexed_settings/indexed_settings_controller.dart ================================================ import 'package:get/get.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; class IndexedSettingsController extends GetxController { RxList siteSort = RxList(); RxList homeSort = RxList(); @override void onInit() { siteSort = AppSettingsController.instance.siteSort; homeSort = AppSettingsController.instance.homeSort; super.onInit(); } void updateSiteSort(int oldIndex, int newIndex) { if (oldIndex < newIndex) { newIndex -= 1; } final String item = siteSort.removeAt(oldIndex); siteSort.insert(newIndex, item); // ignore: invalid_use_of_protected_member AppSettingsController.instance.setSiteSort(siteSort.value); } void updateHomeSort(int oldIndex, int newIndex) { if (oldIndex < newIndex) { newIndex -= 1; } final String item = homeSort.removeAt(oldIndex); homeSort.insert(newIndex, item); // ignore: invalid_use_of_protected_member AppSettingsController.instance.setHomeSort(homeSort.value); } } ================================================ FILE: simple_live_app/lib/modules/settings/indexed_settings/indexed_settings_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/modules/settings/indexed_settings/indexed_settings_controller.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; class IndexedSettingsPage extends GetView { const IndexedSettingsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("主页设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Text( "主页排序 (长按拖动排序,重启后生效)", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Obx( () => ReorderableListView( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), onReorder: controller.updateHomeSort, children: controller.homeSort.map( (key) { var e = Constant.allHomePages[key]!; return ListTile( key: ValueKey(e.title), title: Text(e.title), visualDensity: VisualDensity.compact, leading: Icon(e.iconData), trailing: const Icon(Icons.drag_handle), ); }, ).toList(), ), ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "平台排序 (长按拖动排序,重启后生效)", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Obx( () => ReorderableListView( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), onReorder: controller.updateSiteSort, children: controller.siteSort.map( (key) { var e = Sites.allSites[key]!; return ListTile( key: ValueKey(e.id), visualDensity: VisualDensity.compact, title: Text(e.name), leading: Image.asset( e.logo, width: 24, height: 24, ), trailing: const Icon(Icons.drag_handle), ); }, ).toList(), ), ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/settings/other/other_settings_controller.dart ================================================ import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:path/path.dart' as p; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/services/local_storage_service.dart'; class OtherSettingsController extends BaseController { RxList logFiles = [].obs; var videoOutputDrivers = { "gpu": "gpu", "gpu-next": "gpu-next", "xv": "xv (X11 only)", "x11": "x11 (X11 only)", "vdpau": "vdpau (X11 only)", "direct3d": "direct3d (Windows only)", "sdl": "sdl", "dmabuf-wayland": "dmabuf-wayland", "vaapi": "vaapi", "null": "null", "libmpv": "libmpv", "mediacodec_embed": "mediacodec_embed (Android only)", }; var audioOutputDrivers = { "null": "null (No audio output)", "pulse": "pulse (Linux, uses PulseAudio)", "pipewire": "pipewire (Linux, via Pulse compatibility or native)", "alsa": "alsa (Linux only)", "oss": "oss (Linux only)", "jack": "jack (Linux/macOS, low-latency audio)", "directsound": "directsound (Windows only)", "wasapi": "wasapi (Windows only)", "winmm": "winmm (Windows only, legacy API)", "audiounit": "audiounit (iOS only)", "coreaudio": "coreaudio (macOS only)", "opensles": "opensles (Android only)", "audiotrack": "audiotrack (Android only)", "aaudio": "aaudio (Android only)", "pcm": "pcm (Cross-platform)", "sdl": "sdl (Cross-platform, via SDL library)", "openal": "openal (Cross-platform, OpenAL backend)", "libao": "libao (Cross-platform, uses libao library)", "auto": "auto (Not available)" }; var hardwareDecoder = { "no": "no", "auto": "auto", "auto-safe": "auto-safe", "yes": "yes", "auto-copy": "auto-copy", "d3d11va": "d3d11va", "d3d11va-copy": "d3d11va-copy", "videotoolbox": "videotoolbox", "videotoolbox-copy": "videotoolbox-copy", "vaapi": "vaapi", "vaapi-copy": "vaapi-copy", "nvdec": "nvdec", "nvdec-copy": "nvdec-copy", "drm": "drm", "drm-copy": "drm-copy", "vulkan": "vulkan", "vulkan-copy": "vulkan-copy", "dxva2": "dxva2", "dxva2-copy": "dxva2-copy", "vdpau": "vdpau", "vdpau-copy": "vdpau-copy", "mediacodec": "mediacodec", "mediacodec-copy": "mediacodec-copy", "cuda": "cuda", "cuda-copy": "cuda-copy", "crystalhd": "crystalhd", "rkmpp": "rkmpp" }; @override void onInit() { loadLogFiles(); super.onInit(); } void setLogEnable(e) { AppSettingsController.instance.setLogEnable(e); if (e) { Log.initWriter(); Future.delayed(const Duration(milliseconds: 100), () { loadLogFiles(); }); } else { Log.disposeWriter(); } } void loadLogFiles() async { var supportDir = await getApplicationSupportDirectory(); var logDir = Directory("${supportDir.path}/log"); if (!await logDir.exists()) { await logDir.create(); } logFiles.clear(); await logDir.list().forEach((element) { var file = element as File; var name = p.basename(file.path); var time = file.lastModifiedSync(); var size = file.lengthSync(); logFiles.add(LogFileModel(name, file.path, time, size)); }); //logFiles 名称倒序 logFiles.sort((a, b) => b.time.compareTo(a.time)); } void cleanLog() async { if (AppSettingsController.instance.logEnable.value) { SmartDialog.showToast("请先关闭日志记录"); return; } var supportDir = await getApplicationSupportDirectory(); var logDir = Directory("${supportDir.path}/log"); if (await logDir.exists()) { await logDir.delete(recursive: true); } loadLogFiles(); } void shareLogFile(LogFileModel item) { SharePlus.instance.share(ShareParams( files: [XFile(item.path)], )); } void saveLogFile(LogFileModel item) async { var filePath = await FilePicker.platform.saveFile( allowedExtensions: ['log'], type: FileType.custom, fileName: item.name, bytes: Uint8List(0), ); if (filePath != null) { var file = File(item.path); await file.copy(filePath); SmartDialog.showToast("保存成功"); } } void exportConfig() async { try { // 组装数据 var data = { "type": "simple_live", "platform": Platform.operatingSystem, "version": 1, "time": DateTime.now().millisecondsSinceEpoch, "config": LocalStorageService.instance.settingsBox.toMap(), "shield": LocalStorageService.instance.shieldBox.toMap(), }; var bytes = Uint8List.fromList(utf8.encode(jsonEncode(data))); // FilePicker 直接写入 var inlineSave = Platform.isAndroid || Platform.isIOS || kIsWeb; var path = await FilePicker.platform.saveFile( allowedExtensions: ['json'], type: FileType.custom, fileName: "simple_live_config.json", bytes: inlineSave ? bytes : null, ); if (path == null && !kIsWeb) { SmartDialog.showToast("保存取消"); return; } // 桌面平台需要手动写入 if (!inlineSave && path != null) { await File(path).writeAsBytes(bytes); } SmartDialog.showToast("保存成功"); } catch (e) { Log.logPrint(e); SmartDialog.showToast("导出失败:$e"); } } void importConfig() async { try { var file = await FilePicker.platform.pickFiles( allowedExtensions: ['json'], type: FileType.custom, ); if (file == null) { return; } var filePath = file.files.single.path!; var data = jsonDecode(await File(filePath).readAsString()); if (data["type"] != "simple_live") { SmartDialog.showToast("不支持的配置文件"); return; } // 检查platform if (data["platform"] != Platform.operatingSystem && !await Utils.showAlertDialog("导入配置文件平台不匹配,是否继续导入?", title: "平台不匹配")) { return; } LocalStorageService.instance.settingsBox.clear(); LocalStorageService.instance.shieldBox.clear(); LocalStorageService.instance.settingsBox.putAll(data["config"]); LocalStorageService.instance.shieldBox .putAll(data["shield"].cast()); SmartDialog.showToast("导入成功,重启生效"); } catch (e) { Log.logPrint(e); SmartDialog.showToast("导入失败:$e"); } } void resetDefaultConfig() { Utils.showAlertDialog("是否重置所有配置为默认值?").then((value) { if (value) { LocalStorageService.instance.settingsBox.clear(); LocalStorageService.instance.shieldBox.clear(); SmartDialog.showToast("重置成功,重启生效"); } }); } } class LogFileModel { late String name; late String path; late DateTime time; late int size; LogFileModel(this.name, this.path, this.time, this.size); } ================================================ FILE: simple_live_app/lib/modules/settings/other/other_settings_page.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/settings/other/other_settings_controller.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_menu.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; import 'package:url_launcher/url_launcher_string.dart'; class OtherSettingsPage extends GetView { const OtherSettingsPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("其他设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ SettingsCard( child: Padding( padding: AppStyle.edgeInsetsA4, child: Row( children: [ Expanded( child: TextButton.icon( onPressed: controller.exportConfig, label: const Text("导出配置"), icon: const Icon(Remix.export_line), ), ), Expanded( child: TextButton.icon( onPressed: controller.importConfig, label: const Text("导入配置"), icon: const Icon(Remix.import_line), ), ), Expanded( child: TextButton.icon( onPressed: controller.resetDefaultConfig, label: const Text("重置配置"), icon: const Icon(Remix.restart_line), ), ), ], ), ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "播放器高级设置", style: Get.textTheme.titleSmall, ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Text.rich( TextSpan( text: "请勿随意修改以下设置,除非你知道自己在做什么。\n在修改以下设置前,你应该先查阅", children: [ WidgetSpan( child: GestureDetector( onTap: () { launchUrlString( "https://mpv.io/manual/stable/#video-output-drivers"); }, child: const Text( "MPV的文档", style: TextStyle( color: Colors.blue, fontSize: 12, decoration: TextDecoration.underline, ), ), ), ), ], ), style: const TextStyle(fontSize: 12, color: Colors.grey), ), ), SettingsCard( child: Column( children: [ Obx( () => SettingsSwitch( value: AppSettingsController.instance.customPlayerOutput.value, title: "自定义输出驱动与硬件加速", onChanged: (e) { AppSettingsController.instance.setCustomPlayerOutput(e); }, ), ), AppStyle.divider, Obx( () => SettingsMenu( title: "视频输出驱动(--vo)", value: AppSettingsController.instance.videoOutputDriver.value, valueMap: controller.videoOutputDrivers, onChanged: (e) { AppSettingsController.instance.setVideoOutputDriver(e); }, ), ), AppStyle.divider, Obx( () => SettingsMenu( title: "音频输出驱动(--ao)", value: AppSettingsController.instance.audioOutputDriver.value, valueMap: controller.audioOutputDrivers, onChanged: (e) { AppSettingsController.instance.setAudioOutputDriver(e); }, ), ), AppStyle.divider, Obx( () => SettingsMenu( title: "硬件解码器(--hwdec)", value: AppSettingsController .instance.videoHardwareDecoder.value, valueMap: controller.hardwareDecoder, onChanged: (e) { AppSettingsController.instance.setVideoHardwareDecoder(e); }, ), ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "日志记录", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( children: [ Obx( () => SettingsSwitch( value: AppSettingsController.instance.logEnable.value, title: "开启日志记录", subtitle: "开启后将记录调试日志,可以将日志文件提供给开发者用于排查问题", onChanged: controller.setLogEnable, ), ), ], ), ), ListTile( contentPadding: AppStyle.edgeInsetsL12, visualDensity: VisualDensity.compact, title: Text( "日志列表", style: Get.textTheme.titleSmall, ), trailing: TextButton.icon( onPressed: () { controller.cleanLog(); }, label: const Text("清空日志"), icon: const Icon(Icons.clear_all), ), ), SettingsCard( child: SizedBox( height: 300, child: Obx( () => ListView.separated( itemCount: controller.logFiles.length, separatorBuilder: (context, index) => AppStyle.divider, itemBuilder: (context, index) { var item = controller.logFiles[index]; return ListTile( visualDensity: VisualDensity.compact, contentPadding: AppStyle.edgeInsetsL12.copyWith(right: 4), title: Text(item.name), subtitle: Text(Utils.parseFileSize(item.size)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (!Platform.isLinux) IconButton( onPressed: () { controller.shareLogFile(item); }, icon: const Icon(Icons.share), ), IconButton( onPressed: () { controller.saveLogFile(item); }, icon: const Icon(Icons.save), ), ], ), ); }, ), ), ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/settings/play_settings_page.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; import 'package:simple_live_app/widgets/settings/settings_menu.dart'; import 'package:simple_live_app/widgets/settings/settings_number.dart'; import 'package:simple_live_app/widgets/settings/settings_switch.dart'; class PlaySettingsPage extends GetView { const PlaySettingsPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("直播间设置"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Text( "播放器", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ Obx( () => SettingsSwitch( title: "硬件解码", value: controller.hardwareDecode.value, subtitle: "播放失败可尝试关闭此选项", onChanged: (e) { controller.setHardwareDecode(e); }, ), ), if (Platform.isAndroid) AppStyle.divider, Obx( () => Visibility( visible: Platform.isAndroid, child: SettingsSwitch( title: "兼容模式", subtitle: "若播放卡顿可尝试打开此选项", value: controller.playerCompatMode.value, onChanged: (e) { controller.setPlayerCompatMode(e); }, ), ), ), // AppStyle.divider, // Obx( // () => SettingsNumber( // title: "缓冲区大小", // subtitle: "若播放卡顿可尝试调高此选项", // value: controller.playerBufferSize.value, // min: 32, // max: 1024, // step: 4, // unit: "MB", // onChanged: (e) { // controller.setPlayerBufferSize(e); // }, // ), // ), AppStyle.divider, Obx( () => SettingsSwitch( title: "进入后台自动暂停", value: controller.playerAutoPause.value, onChanged: (e) { controller.setPlayerAutoPause(e); }, ), ), AppStyle.divider, Obx( () => SettingsMenu( title: "画面尺寸", value: controller.scaleMode.value, valueMap: const { 0: "适应", 1: "拉伸", 2: "铺满", 3: "16:9", 4: "4:3", }, onChanged: (e) { controller.setScaleMode(e); }, ), ), AppStyle.divider, Obx( () => SettingsSwitch( title: "使用HTTPS链接", subtitle: "将http链接替换为https", value: controller.playerForceHttps.value, onChanged: (e) { controller.setPlayerForceHttps(e); }, ), ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "直播间", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ Obx( () => SettingsSwitch( title: "进入直播间自动全屏", value: controller.autoFullScreen.value, onChanged: (e) { controller.setAutoFullScreen(e); }, ), ), AppStyle.divider, Obx( () => Visibility( visible: Platform.isAndroid, child: SettingsSwitch( title: "进入小窗隐藏弹幕", value: controller.pipHideDanmu.value, onChanged: (e) { controller.setPIPHideDanmu(e); }, ), ), ), AppStyle.divider, Obx( () => SettingsSwitch( title: "播放器中显示SC", value: controller.playershowSuperChat.value, onChanged: (e) { controller.setPlayerShowSuperChat(e); }, ), ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "清晰度", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( children: [ Obx( () => SettingsMenu( title: "默认清晰度", value: controller.qualityLevel.value, valueMap: const { 0: "最低", 1: "中等", 2: "最高", }, onChanged: (e) { controller.setQualityLevel(e); }, ), ), AppStyle.divider, Obx( () => SettingsMenu( title: "数据网络清晰度", value: controller.qualityLevelCellular.value, valueMap: const { 0: "最低", 1: "中等", 2: "最高", }, onChanged: (e) { controller.setQualityLevelCellular(e); }, ), ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "聊天区", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ Obx( () => SettingsNumber( title: "文字大小", value: controller.chatTextSize.value.toInt(), min: 8, max: 36, onChanged: (e) { controller.setChatTextSize(e.toDouble()); }, ), ), AppStyle.divider, Obx( () => SettingsNumber( title: "上下间隔", value: controller.chatTextGap.value.toInt(), min: 0, max: 12, onChanged: (e) { controller.setChatTextGap(e.toDouble()); }, ), ), AppStyle.divider, Obx( () => SettingsSwitch( title: "气泡样式", value: controller.chatBubbleStyle.value, onChanged: (e) { controller.setChatBubbleStyle(e); }, ), ), ], ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/sync/local_sync/device/sync_device_controller.dart ================================================ import 'dart:convert'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/sync_client_info_model.dart'; import 'package:simple_live_app/requests/sync_client_request.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:simple_live_app/services/sync_service.dart'; class SyncDeviceController extends BaseController { final SyncClinet client; final SyncClientInfoModel info; SyncDeviceController({required this.client, required this.info}); SyncClientRequest request = SyncClientRequest(); Future showOverlayDialog() async { var overlay = await Utils.showAlertDialog( "是否覆盖远端数据?", title: "数据覆盖", confirm: "覆盖", cancel: "不覆盖", ); return overlay; } void syncFollowAndTag() async { try { var overlay = await showOverlayDialog(); SmartDialog.showLoading(msg: "同步中..."); var users = DBService.instance.getFollowList(); var tags = DBService.instance.getFollowTagList(); var data = json.encode(users.map((e) => e.toJson()).toList()); var dataT = json.encode(tags.map((e) => e.toJson()).toList()); await request.syncFollow(client, data, overlay: overlay); // 标签和关注必须同时同步 await request.syncTag(client, dataT, overlay: overlay); SmartDialog.showToast("已同步关注列表和标签"); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void syncHistory() async { try { var overlay = await showOverlayDialog(); SmartDialog.showLoading(msg: "同步中..."); var histores = DBService.instance.getHistores(); var data = json.encode(histores.map((e) => e.toJson()).toList()); await request.syncHistory(client, data, overlay: overlay); SmartDialog.showToast("已同步历史记录"); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void syncBlockedWord() async { try { var overlay = await showOverlayDialog(); SmartDialog.showLoading(msg: "同步中..."); var shieldList = AppSettingsController.instance.shieldList; var data = json.encode(shieldList.toList()); await request.syncBlockedWord(client, data, overlay: overlay); SmartDialog.showToast("已同步屏蔽词"); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void syncBiliAccount() async { try { if (!BiliBiliAccountService.instance.logined.value) { SmartDialog.showToast("未登录哔哩哔哩"); return; } SmartDialog.showLoading(msg: "同步中..."); await request.syncBiliAccount( client, BiliBiliAccountService.instance.cookie); SmartDialog.showToast("已同步哔哩哔哩账号"); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } } ================================================ FILE: simple_live_app/lib/modules/sync/local_sync/device/sync_device_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/sync/local_sync/device/sync_device_controller.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; class SyncDevicePage extends GetView { const SyncDevicePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("同步"), ), body: ListView( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), children: [ SettingsCard( child: ListTile( leading: buildIcon(), title: Text(controller.info.name), subtitle: Text( "${controller.info.type.toUpperCase()} ${controller.info.address}"), ), ), AppStyle.vGap12, SettingsCard( child: Column( children: [ ListTile( leading: const Icon(Remix.heart_line), title: const Text("同步关注列表"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncFollowAndTag(); }, ), AppStyle.divider, ListTile( leading: const Icon(Icons.history), title: const Text("同步观看记录"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncHistory(); }, ), AppStyle.divider, ListTile( leading: const Icon(Remix.shield_keyhole_line), title: const Text("同步弹幕屏蔽词"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncBlockedWord(); }, ), AppStyle.divider, ListTile( leading: const Icon(Remix.account_circle_line), title: const Text("同步哔哩哔哩账号"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncBiliAccount(); }, ), ], ), ), ], ), ); } Widget buildIcon() { var icon = controller.info.type.toLowerCase(); if (icon == "android") { return const Icon(Remix.android_line); } else if (icon == "ios") { return const Icon(Remix.apple_line); } else if (icon == "tv") { return const Icon(Remix.tv_2_line); } else if (icon == "windows") { return const Icon(Remix.microsoft_fill); } else if (icon == "macos") { return const Icon(Remix.mac_line); } else if (icon == "linux") { return const Icon(Remix.ubuntu_line); } else { return const Icon(Remix.device_line); } } } ================================================ FILE: simple_live_app/lib/modules/sync/local_sync/local_sync_controller.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/requests/sync_client_request.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/services/sync_service.dart'; class LocalSyncController extends BaseController { final String? address; LocalSyncController(this.address); @override void onInit() { SyncService.instance.refreshClients(); Future.delayed(Duration.zero, initConnect); super.onInit(); } void initConnect() { if (address != null && address!.isNotEmpty) { addressController.text = address!; connect(); } } TextEditingController addressController = TextEditingController(); SyncClientRequest request = SyncClientRequest(); void connect() async { var address = addressController.text; if (address.isEmpty) { SmartDialog.showToast("请输入地址"); return; } if (address.startsWith('http')) { var uri = Uri.tryParse(address); if (uri != null) { address = uri.host; } } else if (address.contains(':')) { var parts = address.split(":"); address = parts.first; } var client = SyncClinet( id: 'manual', address: address, port: SyncService.httpPort, name: "手动输入", type: Platform.operatingSystem, ); connectClient(client); } void connectClient(SyncClinet client) async { try { SmartDialog.showLoading(msg: "连接中..."); var info = await request.getClientInfo(client); AppNavigator.toSyncDevice(client, info); } catch (e) { SmartDialog.showToast("连接失败:$e"); } finally { SmartDialog.dismiss(); } } void toScanQr() async { var result = await Get.toNamed(RoutePath.kSyncScan); if (result == null || result.isEmpty) { return; } var addressList = (result as String).split(";"); if (addressList.length >= 2) { //弹窗选择 showPickerAddress(addressList); } else { addressController.text = result; //connect(); } } void showPickerAddress(List addressList) { SmartDialog.showToast("扫描到多个地址,请选择一个连接"); Utils.showBottomSheet( title: '请选择地址', child: ListView.builder( itemBuilder: (_, i) { return ListTile( title: Text(addressList[i]), onTap: () { Get.back(); addressController.text = addressList[i]; // connect(); }, ); }, itemCount: addressList.length, ), ); } void showInfo() { Utils.showBottomSheet( title: "本机信息", child: Column( children: [ Visibility( visible: SyncService.instance.httpRunning.value, child: GestureDetector( onTap: () { Get.back(); }, child: QrImageView( data: SyncService.instance.ipAddress.value, version: QrVersions.auto, backgroundColor: Colors.white, padding: AppStyle.edgeInsetsA12, size: 200, ), ), ), AppStyle.vGap24, Visibility( visible: SyncService.instance.httpRunning.value, child: Text( '服务已启动:${SyncService.instance.ipAddress.value.split(';').map((e) => '$e:${SyncService.httpPort}').join(';')}', textAlign: TextAlign.center, ), ), Visibility( visible: !SyncService.instance.httpRunning.value, child: Text( 'HTTP服务未启动:${SyncService.instance.httpErrorMsg},请尝试重启应用', textAlign: TextAlign.center, ), ), AppStyle.vGap12, Visibility( visible: SyncService.instance.httpRunning.value, child: const Text( "请使用其他Simple Live客户端扫描上方二维码\n建立连接后可选择需要同步的数据", textAlign: TextAlign.center, ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/sync/local_sync/local_sync_page.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/modules/sync/local_sync/local_sync_controller.dart'; import 'package:simple_live_app/services/sync_service.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; class LocalSyncPage extends GetView { const LocalSyncPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('局域网数据同步'), actions: [ TextButton.icon( onPressed: controller.showInfo, icon: const Icon(Icons.qr_code), label: const Text("信息"), ), ], ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ SettingsCard( child: Padding( padding: AppStyle.edgeInsetsA12, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisSize: MainAxisSize.min, children: [ TextField( controller: controller.addressController, onSubmitted: (e) { controller.connect(); }, decoration: InputDecoration( labelText: '客户端地址', hintText: '请输入地址或扫码自动填写', contentPadding: AppStyle.edgeInsetsH12, border: const OutlineInputBorder(), suffixIcon: Visibility( visible: Platform.isAndroid || Platform.isIOS, child: TextButton.icon( onPressed: controller.toScanQr, icon: const Icon(Remix.qr_scan_line), label: const Text("扫一扫"), ), ), ), ), AppStyle.vGap12, ElevatedButton( onPressed: () { controller.connect(); }, child: const Text("连接"), ), ], ), ), ), AppStyle.vGap12, ListTile( title: Obx( () => Text( "已发现设备(${SyncService.instance.scanClients.length})", style: Get.textTheme.titleSmall, ), ), visualDensity: VisualDensity.compact, contentPadding: AppStyle.edgeInsetsH12, trailing: IconButton( visualDensity: VisualDensity.compact, onPressed: () { SyncService.instance.refreshClients(); }, icon: const Icon(Icons.refresh), ), ), SettingsCard( child: Obx( () => ListView.separated( shrinkWrap: true, padding: EdgeInsets.zero, physics: const NeverScrollableScrollPhysics(), separatorBuilder: (BuildContext context, int index) => AppStyle.divider, itemCount: SyncService.instance.scanClients.length, itemBuilder: (BuildContext context, int index) { var client = SyncService.instance.scanClients[index]; return ListTile( title: Text(client.name), subtitle: Text(client.address), trailing: const Icon(Icons.chevron_right), onTap: () { controller.connectClient(client); }, ); }, ), ), ), AppStyle.vGap12, const Text( "如果无法扫描到设备,请手动输入地址", textAlign: TextAlign.center, style: TextStyle( color: Colors.grey, fontSize: 14, ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/sync/local_sync/scan_qr/sync_scan_qr_controller.dart ================================================ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/routes/route_path.dart'; class SyncScanQRControlelr extends BaseController { final GlobalKey qrKey = GlobalKey(debugLabel: 'QR'); QRViewController? qrController; StreamSubscription? barcodeStreamSubscription; bool pause = false; void onQRViewCreated(QRViewController controller) { qrController = controller; barcodeStreamSubscription = qrController!.scannedDataStream.listen((scanData) async { Log.d(scanData.toString()); if (pause) { return; } pause = true; // 扫码成功后暂停摄像头 await controller.pauseCamera(); var code = scanData.code ?? ""; // 处理扫码结果 if (code.isEmpty) { pause = false; await controller.resumeCamera(); return; } // 如果是5位字符串,为房间号 if (code.length == 5) { Get.offAndToNamed(RoutePath.kRemoteSyncRoom, arguments: code); return; } else { var addressList = code.split(";"); if (addressList.length >= 2) { //弹窗选择 showPickerAddress(addressList); } else { Get.back(result: code); } } }); } void showPickerAddress(List addressList) async { SmartDialog.showToast("扫描到多个地址,请选择一个连接"); var address = await Utils.showBottomSheet( title: '请选择地址', child: ListView.builder( itemBuilder: (_, i) { return ListTile( title: Text(addressList[i]), onTap: () { Get.back(result: addressList[i]); }, ); }, itemCount: addressList.length, ), ); if (address != null && address.isNotEmpty) { Get.back(result: address); } } @override void onClose() { barcodeStreamSubscription?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/sync/local_sync/scan_qr/sync_scan_qr_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart'; import 'package:simple_live_app/modules/sync/local_sync/scan_qr/sync_scan_qr_controller.dart'; class SyncScanQRPage extends GetView { const SyncScanQRPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('扫描二维码'), actions: [ IconButton( onPressed: () { controller.qrController?.toggleFlash(); }, icon: const Icon(Icons.flash_on), ), // 反转摄像头 IconButton( onPressed: () { controller.qrController?.flipCamera(); }, icon: const Icon(Icons.flip_camera_android), ), ], ), body: Stack( children: [ QRView( key: controller.qrKey, onQRViewCreated: controller.onQRViewCreated, ), const ScanRectangle(), ], ), ); } } class ScanRectangle extends StatefulWidget { const ScanRectangle({super.key}); @override State createState() => _ScanRectangleState(); } class _ScanRectangleState extends State with SingleTickerProviderStateMixin { late AnimationController animeController; late Animation animation; @override void initState() { animeController = AnimationController(duration: const Duration(seconds: 2), vsync: this); animeController.addStatusListener((status) { if (status == AnimationStatus.completed) { animeController.reverse(); } else if (status == AnimationStatus.dismissed) { animeController.forward(); } }); animation = Tween( begin: const Offset(0, 0), end: const Offset(0, 1), ).animate(animeController); animeController.forward(); super.initState(); } @override Widget build(BuildContext context) { return Center( child: Container( height: 240, width: 240, decoration: BoxDecoration( border: Border.all( color: Colors.grey.withAlpha(50), width: 2, ), ), child: SlideTransition( position: animation, child: Container( height: 240, width: 240, decoration: const BoxDecoration( border: Border( top: BorderSide( width: 2, color: Colors.green, ), ), ), ), ), ), ); } @override void dispose() { animeController.dispose(); super.dispose(); } } ================================================ FILE: simple_live_app/lib/modules/sync/remote_sync/room/remote_sync_room_controller.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:simple_live_app/services/signalr_service.dart'; class RemoteSyncRoomController extends BaseController { final String roomId; final SignalRService signalR = SignalRService(); RemoteSyncRoomController(this.roomId) { if (roomId.isNotEmpty) { currentRoomId.value = roomId; } } StreamSubscription? _roomDestroyedSubscription; StreamSubscription? _roomUserUpdatedSubscription; StreamSubscription? _onFavoriteSubscription; StreamSubscription? _onHistorySubscription; StreamSubscription? _onShieldWordSubscription; StreamSubscription? _onBiliAccountSubscription; var currentRoomId = "--".obs; RxList roomUsers = [].obs; Timer? _timer; var countDown = 600.obs; @override void onInit() { connect(); super.onInit(); } void connect() async { listenSignalR(); await signalR.connect(); if (signalR.state == SignalRConnectionState.connected) { if (roomId.isEmpty) { createRoom(); } else { joinRoom(roomId); } } } void createRoom() async { try { var resp = await signalR.createRoom(); if (resp.isSuccess) { currentRoomId.value = resp.data!; _startTimer(); } else { SmartDialog.showToast(resp.message); Get.back(); } } catch (e) { SmartDialog.showToast("创建房间失败"); Get.back(); } } void _startTimer() { // 倒计时5分钟,自动关闭页面 countDown.value = 600; _timer = Timer.periodic(const Duration(seconds: 1), (timer) { countDown--; if (countDown <= 0) { timer.cancel(); Get.back(); } }); } void joinRoom(String roomId) async { try { var resp = await signalR.joinRoom(roomId); if (!resp.isSuccess) { SmartDialog.showToast(resp.message); Get.back(); } } catch (e) { SmartDialog.showToast("加入房间失败"); Get.back(); } } void listenSignalR() { _roomDestroyedSubscription = signalR.onRoomDestroyedStream.listen((roomId) { SmartDialog.showToast("房间已被销毁"); Get.back(); }); _roomUserUpdatedSubscription = signalR.onRoomUserUpdatedStream.listen( (roomUsers) { this.roomUsers.assignAll(roomUsers); }, ); _onFavoriteSubscription = signalR.onFavoriteStream.listen((data) { onReceiveFavorite(data.$1, data.$2); }); _onHistorySubscription = signalR.onHistoryStream.listen((data) { onReceiveHistory(data.$1, data.$2); }); _onShieldWordSubscription = signalR.onShieldWordStream.listen((data) { onReceiveShieldWord(data.$1, data.$2); }); _onBiliAccountSubscription = signalR.onBiliAccountStream.listen((data) { onReceiveBiliAccount(data.$1, data.$2); }); } void onReceiveFavorite(bool overlay, String data) async { try { var jsonBody = json.decode(data); if (overlay) { await DBService.instance.followBox.clear(); } for (var item in jsonBody) { var user = FollowUser.fromJson(item); await DBService.instance.followBox.put(user.id, user); } SmartDialog.showToast('已同步关注用户列表'); EventBus.instance.emit(Constant.kUpdateFollow, 0); SmartDialog.showToast("已同步关注列表"); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } void onReceiveHistory(bool overlay, String data) async { try { var jsonBody = json.decode(data); if (overlay) { await DBService.instance.historyBox.clear(); } for (var item in jsonBody) { var history = History.fromJson(item); if (DBService.instance.historyBox.containsKey(history.id)) { var old = DBService.instance.historyBox.get(history.id); //如果本地的更新时间比较新,就不更新 if (old!.updateTime.isAfter(history.updateTime)) { continue; } } await DBService.instance.addOrUpdateHistory(history); } SmartDialog.showToast('已同步历史记录'); EventBus.instance.emit(Constant.kUpdateHistory, 0); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } void onReceiveShieldWord(bool overlay, String data) async { try { var jsonBody = json.decode(data); if (overlay) { AppSettingsController.instance.clearShieldList(); } for (var item in jsonBody) { // add to Hive AppSettingsController.instance.addShieldList(item); } SmartDialog.showToast('已同步屏蔽词'); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } void onReceiveBiliAccount(bool overlay, String data) async { try { var jsonBody = json.decode(data); var cookie = jsonBody['cookie']; BiliBiliAccountService.instance.setCookie(cookie); BiliBiliAccountService.instance.loadUserInfo(); SmartDialog.showToast('已同步哔哩哔哩账号'); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } Future showOverlayDialog() async { var overlay = await Utils.showAlertDialog( "是否覆盖远端数据?", title: "数据覆盖", confirm: "覆盖", cancel: "不覆盖", ); return overlay; } void syncFollow() async { try { if (roomUsers.length <= 1) { SmartDialog.showToast("无设备连接"); return; } var overlay = await showOverlayDialog(); SmartDialog.showLoading(msg: "发送中..."); var users = DBService.instance.getFollowList(); var data = json.encode(users.map((e) => e.toJson()).toList()); var resp = await signalR.sendContent( roomName: currentRoomId.value, action: "SendFavorite", overlay: overlay, content: data, ); if (resp.isSuccess) { SmartDialog.showToast("已发送关注列表"); } else { SmartDialog.showToast("发送失败:${resp.message}"); } } catch (e) { SmartDialog.showToast("发送失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void syncHistory() async { try { if (roomUsers.length <= 1) { SmartDialog.showToast("无设备连接"); return; } var overlay = await showOverlayDialog(); SmartDialog.showLoading(msg: "发送中..."); var histores = DBService.instance.getHistores(); var data = json.encode(histores.map((e) => e.toJson()).toList()); var resp = await signalR.sendContent( roomName: currentRoomId.value, action: "SendHistory", overlay: overlay, content: data, ); if (resp.isSuccess) { SmartDialog.showToast("已发送历史记录"); } else { SmartDialog.showToast("发送失败:${resp.message}"); } } catch (e) { SmartDialog.showToast("发送失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void syncBlockedWord() async { try { if (roomUsers.length <= 1) { SmartDialog.showToast("无设备连接"); return; } var overlay = await showOverlayDialog(); SmartDialog.showLoading(msg: "发送中..."); var shieldList = AppSettingsController.instance.shieldList; var data = json.encode(shieldList.toList()); var resp = await signalR.sendContent( roomName: currentRoomId.value, action: "SendShieldWord", overlay: overlay, content: data, ); if (resp.isSuccess) { SmartDialog.showToast("已发送屏蔽词"); } else { SmartDialog.showToast("发送失败:${resp.message}"); } } catch (e) { SmartDialog.showToast("发送失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void syncBiliAccount() async { try { if (roomUsers.length <= 1) { SmartDialog.showToast("无设备连接"); return; } if (!BiliBiliAccountService.instance.logined.value) { SmartDialog.showToast("未登录哔哩哔哩"); return; } SmartDialog.showLoading(msg: "发送中..."); var resp = await signalR.sendContent( roomName: currentRoomId.value, action: "SendBiliAccount", overlay: true, content: json.encode({ "cookie": BiliBiliAccountService.instance.cookie, }), ); if (resp.isSuccess) { SmartDialog.showToast("已发送哔哩哔哩账号"); } else { SmartDialog.showToast("发送失败:${resp.message}"); } } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } finally { SmartDialog.dismiss(); } } void showQRInfo() { Utils.showBottomSheet( title: "房间信息", child: Column( children: [ QrImageView( data: currentRoomId.value, version: QrVersions.auto, backgroundColor: Colors.white, padding: AppStyle.edgeInsetsA12, size: 200, ), AppStyle.vGap24, Text( currentRoomId.value, textAlign: TextAlign.center, style: Get.textTheme.titleLarge, ), const Text( "请使用其他Simple Live客户端扫描上方二维码\n建立连接后可选择需要同步的数据", textAlign: TextAlign.center, ), ], ), ); } @override void onClose() { _timer?.cancel(); _roomDestroyedSubscription?.cancel(); _roomUserUpdatedSubscription?.cancel(); _onFavoriteSubscription?.cancel(); _onHistorySubscription?.cancel(); _onShieldWordSubscription?.cancel(); _onBiliAccountSubscription?.cancel(); signalR.dispose(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/modules/sync/remote_sync/room/remote_sync_room_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/sync/remote_sync/room/remote_sync_room_controller.dart'; import 'package:simple_live_app/services/signalr_service.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; class RemoteSyncRoomPage extends GetView { const RemoteSyncRoomPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("数据同步"), actions: [ Padding( padding: AppStyle.edgeInsetsH12, child: StreamBuilder( stream: controller.signalR.stateStream, builder: (context, snapshot) { if (snapshot.hasData) { switch (snapshot.data) { case SignalRConnectionState.connected: return Row( children: [ Container( width: 8, height: 8, decoration: const BoxDecoration( color: Colors.green, shape: BoxShape.circle, ), ), AppStyle.hGap8, const Text( '已连接', style: TextStyle( fontSize: 14, ), ), ], ); case SignalRConnectionState.disconnected: return Row( children: [ Container( width: 8, height: 8, decoration: const BoxDecoration( color: Colors.red, shape: BoxShape.circle, ), ), AppStyle.hGap8, const Text( '断开连接', style: TextStyle( fontSize: 14, ), ), ], ); default: return const Row( children: [ SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, ), ), Text( '连接中', style: TextStyle( fontSize: 14, ), ), ], ); } } return const SizedBox(); }, ), ), ], ), body: ListView( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), children: [ Visibility( visible: controller.roomId.isEmpty, child: SettingsCard( child: ListTile( visualDensity: VisualDensity.compact, leading: const Icon(Remix.timer_line), title: Obx( () => Text( "${controller.countDown.value}秒后房间将会自动关闭", style: const TextStyle(fontSize: 14), ), ), ), ), ), Padding( padding: AppStyle.edgeInsetsA12, child: Text( "房间号", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Obx( () => ListTile( contentPadding: AppStyle.edgeInsetsL12, title: SelectableText( controller.currentRoomId.value, style: Theme.of(context).textTheme.titleLarge, ), trailing: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon( Icons.copy, size: 20, ), onPressed: () { Utils.copyToClipboard(controller.currentRoomId.value); }, ), IconButton( icon: const Icon( Icons.qr_code, size: 20, ), onPressed: () { controller.showQRInfo(); }, ), AppStyle.hGap4, ], ), ), ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 12), child: Text( "同步数据至其他设备", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Remix.heart_line), title: const Text("发送关注列表"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncFollow(); }, ), AppStyle.divider, ListTile( leading: const Icon(Icons.history), title: const Text("发送观看记录"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncHistory(); }, ), AppStyle.divider, ListTile( leading: const Icon(Remix.shield_keyhole_line), title: const Text("发送弹幕屏蔽词"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncBlockedWord(); }, ), AppStyle.divider, ListTile( leading: const Icon(Remix.account_circle_line), title: const Text("发送哔哩哔哩账号"), trailing: const Icon(Icons.chevron_right), onTap: () { controller.syncBiliAccount(); }, ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 12), child: Text( "已连接设备", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Obx( () => ListView.separated( padding: EdgeInsets.zero, itemCount: controller.roomUsers.length, shrinkWrap: true, separatorBuilder: (context, index) => AppStyle.divider, physics: const NeverScrollableScrollPhysics(), itemBuilder: (BuildContext context, int index) { var user = controller.roomUsers[index]; return ListTile( visualDensity: VisualDensity.compact, leading: SizedBox( width: 48, height: 48, child: Center( child: buildIcon(user.platform), ), ), title: Text.rich( TextSpan( text: user.shortId, style: const TextStyle(fontSize: 16), children: user.isCreator! ? [ WidgetSpan( child: Container( margin: AppStyle.edgeInsetsL4, padding: AppStyle.edgeInsetsH4, decoration: BoxDecoration( border: Border.all(color: Colors.blue), borderRadius: BorderRadius.circular(4), ), child: const Text( "创建者", style: TextStyle( color: Colors.blue, fontSize: 12, ), ), ), ), ] : null, ), ), subtitle: Text("${user.app} - v${user.version}"), trailing: Visibility( visible: controller.signalR.hubConnection?.connectionId == user.connectionId, child: const Text( "本机", ), ), ); }, ), ), ) ], ), ); } Widget buildIcon(String platform) { if (platform == "android") { return const Icon(Remix.android_line); } else if (platform == "ios") { return const Icon(Remix.apple_line); } else if (platform == "tv") { return const Icon(Remix.tv_2_line); } else if (platform == "windows") { return const Icon(Remix.microsoft_fill); } else if (platform == "xbox") { return const Icon(Remix.xbox_line); } else if (platform == "macos") { return const Icon(Remix.mac_line); } else if (platform == "linux") { return const Icon(Remix.ubuntu_line); } else { return const Icon(Remix.device_line); } } } ================================================ FILE: simple_live_app/lib/modules/sync/remote_sync/webdav/remote_sync_webdav_config_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart'; import 'package:simple_live_app/widgets/none_border_circular_textfield.dart'; class RemoteSyncWebDAVConfigPage extends StatefulWidget { const RemoteSyncWebDAVConfigPage({super.key}); @override State createState() => _RemoteSyncWebDAVConfigPageState(); } class _RemoteSyncWebDAVConfigPageState extends State { late TextEditingController _urlController; late TextEditingController _userNameController; late TextEditingController _passwordController; @override void initState() { _urlController = TextEditingController(); _userNameController = TextEditingController(); _passwordController = TextEditingController(); super.initState(); } @override void dispose() { _urlController.dispose(); _userNameController.dispose(); _passwordController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("WebDAV账号配置"), centerTitle: true, actions: [ IconButton( icon: const Icon(Icons.help_outline), onPressed: () { Utils.showInformationHelpDialog( content: [ const Text("此功能可以将您的数据备份到 WebDAV 服务器中或者进行数据恢复.\n"), const Text( "WebDAV 服务器地址请以 http:// 或 https:// 开头,如坚果云(点击复制):"), Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: InkWell( onTap: () { Clipboard.setData(const ClipboardData( text: "https://dav.jianguoyun.com/dav/")); SmartDialog.showToast("复制成功"); }, child: const Text("https://dav.jianguoyun.com/dav/"), ), ), ], ); }, ), ], ), body: GetX( builder: (controller) { return SingleChildScrollView( child: Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ NoneBorderCircularTextField( editingController: _urlController, labelText: "WebDAV服务器地址", hintText: "请以http:// 或 http:// 开头", prefixIcon: const Icon(Icons.public), trailing: InkWell( child: const Icon( Icons.cancel, size: 20, ), onTap: () => _urlController.clear(), ), ), NoneBorderCircularTextField( editingController: _userNameController, labelText: "账号", prefixIcon: const Icon(Icons.account_circle), trailing: InkWell( child: const Icon( Icons.cancel, size: 20, ), onTap: () => _userNameController.clear()), ), NoneBorderCircularTextField( editingController: _passwordController, labelText: "密码", prefixIcon: const Icon(Icons.lock), obscureText: controller.passwordVisible.value, trailing: Row( mainAxisSize: MainAxisSize.min, children: [ InkWell( child: const Icon( Icons.cancel, size: 20, ), onTap: () => _passwordController.clear(), ), AppStyle.hGap12, InkWell( child: controller.passwordVisible.value ? const Icon(Icons.visibility_off) : const Icon(Icons.visibility), onTap: () { controller.changePasswordVisible(); }, ), ], ), ), Padding( padding: const EdgeInsets.only(top: 5, bottom: 15), child: MaterialButton( minWidth: double.infinity, color: Theme.of(context).primaryColor, focusElevation: 0, elevation: 0, highlightElevation: 4, height: 40, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(8.0)), ), child: const Text( "登录", style: TextStyle(color: Colors.white), ), onPressed: () { controller.doWebDAVLogin( _urlController.text, _userNameController.text, _passwordController.text, ); }, ), ) ], ), ), ); }, ), ); } } ================================================ FILE: simple_live_app/lib/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart ================================================ import 'dart:convert'; import 'dart:io'; import 'dart:isolate'; import 'dart:typed_data'; import 'package:archive/archive.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/app/utils/archive.dart'; import 'package:simple_live_app/app/utils/document.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:simple_live_app/modules/sync/remote_sync/webdav/webdav_client.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:simple_live_app/services/local_storage_service.dart'; class RemoteSyncWebDAVController extends BaseController { // ui var passwordVisible = true.obs; // ui-用户选择是否同步 var isSyncFollows = true.obs; var isSyncHistories = true.obs; var isSyncBlockWord = true.obs; var isSyncBilibiliAccount = true.obs; late DAVClient davClient; var user = "--".obs; var lastRecoverTime = "--".obs; var lastUploadTime = "--".obs; final _userFollowJsonName = 'SimpleLive_follows.json'; final _userHistoriesJsonName = 'SimpleLive_histories.json'; final _userBlockedWordJsonName = 'SimpleLive_blocked_word.json'; final _userBilibiliAccountJsonName = 'SimpleLive_bilibili_account.json'; final _userSettingsJsonName = 'SimpleLive_Settings.json'; final _userTagsJsonName = 'SimpleLive_Tags.json'; @override void onInit() { doWebDAVInit(); super.onInit(); } // webDAV 逻辑 // 初始化webDAV void doWebDAVInit() { var uri = LocalStorageService.instance .getValue(LocalStorageService.kWebDAVUri, ""); if (uri.isEmpty) { notLogin.value = true; } else { user.value = LocalStorageService.instance .getValue(LocalStorageService.kWebDAVUser, ""); var password = LocalStorageService.instance .getValue(LocalStorageService.kWebDAVPassword, ""); davClient = DAVClient(uri, user.value, password); // 从未同步过默认为最新数据 lastRecoverTime.value = Utils.parseTime( DateTime.fromMillisecondsSinceEpoch( LocalStorageService.instance.getValue( LocalStorageService.kWebDAVLastRecoverTime, DateTime.now().millisecondsSinceEpoch, ), ), ); lastUploadTime.value = Utils.parseTime( DateTime.fromMillisecondsSinceEpoch( LocalStorageService.instance.getValue( LocalStorageService.kWebDAVLastUploadTime, DateTime.now().millisecondsSinceEpoch, ), ), ); checkIsLogin(); } } // 检查webDAV登录状态 Future checkIsLogin() async { try { // 返回登录结果 bool value = await davClient.pingCompleter.future; notLogin.value = !value; } catch (e) { Log.e("$e", StackTrace.current); notLogin.value = true; } } // WebDAV登录 void doWebDAVLogin( String webDAVUri, String webDAVUser, String webDAVPassword) async { // 确认登录 davClient = DAVClient(webDAVUri, webDAVUser, webDAVPassword); await checkIsLogin(); if (!notLogin.value) { // 保存到本地 LocalStorageService.instance .setValue(LocalStorageService.kWebDAVUri, webDAVUri); LocalStorageService.instance .setValue(LocalStorageService.kWebDAVUser, webDAVUser); user.value = webDAVUser; LocalStorageService.instance .setValue(LocalStorageService.kWebDAVPassword, webDAVPassword); Get.back(); SmartDialog.showToast("登录成功!"); } else { SmartDialog.showToast("WebDAV账号密码验证失败,请重新输入!"); } } // WebDAV登出 @override Future onLogout() async { var result = await Utils.showAlertDialog("确定要登出WebDAV账号?", title: "退出登录"); if (result) { // 清除本地账号数据 LocalStorageService.instance.setValue(LocalStorageService.kWebDAVUri, ""); LocalStorageService.instance .setValue(LocalStorageService.kWebDAVUser, ""); LocalStorageService.instance .setValue(LocalStorageService.kWebDAVPassword, ""); notLogin.value = true; } } // webDAV上传到云端 Future doWebDAVUpload() async { SmartDialog.showLoading(msg: "正在上传到云端"); _backupData().then((value) async { SmartDialog.dismiss(); if (value.isNotEmpty) { var result = await davClient.backup(Uint8List.fromList(value)); if (result) { SmartDialog.showToast("上传成功"); DateTime uploadTime = DateTime.now(); lastUploadTime.value = Utils.parseTime(uploadTime); LocalStorageService.instance.setValue( LocalStorageService.kWebDAVLastUploadTime, uploadTime.millisecondsSinceEpoch); } else { Log.e("备份失败", StackTrace.current); SmartDialog.showToast("上传失败"); } } else { SmartDialog.showToast("上传失败"); } }); } // 备份所有数据 Future> _backupData() async { final archive = Archive(); List zipBytes = []; // 获取本地备份路径 var dir = (await getApplicationSupportDirectory()).path; var profile = Directory(join(dir, 'backup')); if (!profile.existsSync()) { profile.createSync(); } try { // archive.add(filepath, data_map) 会导致文件损坏 // follows var userFollowList = DBService.instance.getFollowList(); var dataFollowsMap = { 'data': userFollowList.map((e) => e.toJson()).toList() }; final userFollowJsonFile = File(join(profile.path, _userFollowJsonName)); await userFollowJsonFile.writeAsString(jsonEncode(dataFollowsMap)); // 用户自定义标签 var userTagsList = DBService.instance.getFollowTagList(); var dataTagsMap = {'data': userTagsList.map((e) => e.toJson()).toList()}; var userTagsJsonFile = File(join(profile.path, _userTagsJsonName)); await userTagsJsonFile.writeAsString(jsonEncode(dataTagsMap)); // histories var userHistoriesList = DBService.instance.getHistores(); var dataHistoriesMap = { 'data': userHistoriesList.map((e) => e.toJson()).toList() }; final userHistoriesJsonFile = File(join(profile.path, _userHistoriesJsonName)); await userHistoriesJsonFile.writeAsString(jsonEncode(dataHistoriesMap)); // blocked_word var userShieldList = AppSettingsController.instance.shieldList; var dataShieldListMap = {'data': userShieldList.toList()}; final userBlockedWordJsonFile = File(join(profile.path, _userBlockedWordJsonName)); await userBlockedWordJsonFile .writeAsString(jsonEncode(dataShieldListMap)); // bilibili_account var userBiliAccountCookieMap = { 'data': {'cookie': BiliBiliAccountService.instance.cookie} }; final bilibiliAccountJsonFile = File(join(profile.path, _userBilibiliAccountJsonName)); await bilibiliAccountJsonFile .writeAsString(jsonEncode(userBiliAccountCookieMap)); // settings var settingList = LocalStorageService.instance.settingsBox.toMap(); var dataSettingListMap = {'data': settingList}; final settingJsonFile = File(join(profile.path, _userSettingsJsonName)); await settingJsonFile.writeAsString(jsonEncode(dataSettingListMap)); // 遍历profile路径下的所有文件压缩 await archive.addDirectoryToArchive(profile.path, profile.path); final zipEncoder = ZipEncoder(); zipBytes = zipEncoder.encode(archive); profile.clearSync(); } catch (e) { Log.logPrint(e); SmartDialog.showToast("备份失败:$e"); } return zipBytes; } // webDAV恢复到本地 void doWebDAVRecovery() async { SmartDialog.showLoading(msg: "正在恢复到本地"); final data = await davClient.recovery(); final archive = await Isolate.run(() { final zipDecoder = ZipDecoder(); return zipDecoder.decodeBytes(data); }); for (ArchiveFile file in archive) { await _recovery(file); } SmartDialog.dismiss(); SmartDialog.showToast('同步完成'); DateTime recoverTime = DateTime.now(); lastRecoverTime.value = Utils.parseTime(recoverTime); LocalStorageService.instance.setValue( LocalStorageService.kWebDAVLastRecoverTime, recoverTime.millisecondsSinceEpoch); } Future _recovery(ArchiveFile file) async { if (file.isFile && file.name.endsWith('.json')) { var jsonString = utf8.decode(file.content); var jsonData = json.decode(jsonString)['data']; // 同步follows if (file.name == _userFollowJsonName && isSyncFollows.value) { // 当前云优先 try { // 清空本地关注列表 await DBService.instance.followBox.clear(); for (var item in jsonData) { var user = FollowUser.fromJson(item); await DBService.instance.followBox.put(user.id, user); } Log.i('已同步关注用户列表'); } catch (e) { Log.e('同步关注用户列表失败: $e', StackTrace.current); } } else if (file.name == _userHistoriesJsonName && isSyncHistories.value) { try { for (var item in jsonData) { var history = History.fromJson(item); if (DBService.instance.historyBox.containsKey(history.id)) { var old = DBService.instance.historyBox.get(history.id); //如果本地的更新时间比较新,就不更新 if (old!.updateTime.isAfter(history.updateTime)) { continue; } } await DBService.instance.addOrUpdateHistory(history); } Log.i('已同步用户观看历史记录'); } catch (e) { Log.e('同步用户观看历史记录失败: $e', StackTrace.current); } } else if (file.name == _userBlockedWordJsonName && isSyncBlockWord.value) { try { for (var keyword in jsonData) { AppSettingsController.instance.addShieldList(keyword.trim()); } Log.i('已同步用户屏蔽词'); } catch (e) { Log.e('同步用户屏蔽词失败:$e', StackTrace.current); } } else if (file.name == _userBilibiliAccountJsonName && isSyncBilibiliAccount.value) { try { var cookie = jsonData['cookie']; BiliBiliAccountService.instance.setCookie(cookie); BiliBiliAccountService.instance.loadUserInfo(); Log.i('已同步哔哩哔哩账号'); } catch (e) { Log.e('同步哔哩哔哩账号失败:$e', StackTrace.current); } } else if (file.name == _userSettingsJsonName) { try { await LocalStorageService.instance.settingsBox.clear(); LocalStorageService.instance.settingsBox.putAll(jsonData); Log.i('已同步用户设置'); } catch (e) { Log.e("同步用户设置失败:$e", StackTrace.current); } } else if (file.name == _userTagsJsonName && isSyncFollows.value) { try { // 标签功能和关注具有依赖关系,必须同时同步 // 清空本地标签列表 await DBService.instance.tagBox.clear(); for (var item in jsonData) { var tag = FollowUserTag.fromJson(item); await DBService.instance.tagBox.put(tag.id, tag); // 插入之后验证 var insertedTag = DBService.instance.tagBox.get(tag.id); Log.i('Inserted tag: ${insertedTag?.tag}'); } EventBus.instance.emit(Constant.kUpdateFollow, 0); Log.i('已同步用户自定义标签'); } catch (e) { Log.e('同步用户自定义标签失败:$e', StackTrace.current); } } else { return; } } else { Log.i('不是正确的文件名'); } } // ui控制--密码可见控制 void changePasswordVisible() { passwordVisible.value = !passwordVisible.value; } void changeIsSyncFollows() { isSyncFollows.value = !isSyncFollows.value; } void changeIsSyncHistories() { isSyncHistories.value = !isSyncHistories.value; } void changeIsSyncBlockWord() { isSyncBlockWord.value = !isSyncBlockWord.value; } void changeIsSyncBilibiliAccount() { isSyncBilibiliAccount.value = !isSyncBilibiliAccount.value; } } ================================================ FILE: simple_live_app/lib/modules/sync/remote_sync/webdav/remote_sync_webdav_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; class RemoteSyncWebDAVPage extends GetView { const RemoteSyncWebDAVPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("WebDAV同步"), ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ SettingsCard( child: Obx( () => Column( children: controller.notLogin.value ? [ ListTile( title: const Text("点击登录"), leading: const Icon(Icons.login), subtitle: const Text("登录后可以同步您的所有数据"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.toNamed(RoutePath.kRemoteSyncWebDavConfig); }, ), ] : [ ListTile( title: const Text("已登录"), leading: const Icon(Icons.cloud_circle_outlined), subtitle: Text(controller.user.value), trailing: const Icon(Icons.logout), onTap: () { controller.onLogout(); }, ), AppStyle.divider, ListTile( title: const Text("上传到云端"), subtitle: Text("上次上传:${controller.lastUploadTime}"), leading: const Icon(Icons.cloud_upload_outlined), trailing: const Icon(Icons.chevron_right), onTap: () { controller.doWebDAVUpload(); }, ), AppStyle.divider, ListTile( title: const Text("恢复到本地"), subtitle: Text("上次恢复:${controller.lastRecoverTime}"), leading: const Icon(Icons.cloud_download_outlined), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.settings), onPressed: showSetting, ), const Icon(Icons.chevron_right), ], ), onTap: () { controller.doWebDAVRecovery(); }, onLongPress: showSetting, ), ], ), ), ), ], ), ); } void showSetting() { Utils.showBottomSheet( title: '同步选项', child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ AppStyle.divider, Obx( () => CheckboxListTile( secondary: const Icon(Remix.heart_line), title: const Text("同步关注列表"), value: controller.isSyncFollows.value, controlAffinity: ListTileControlAffinity.trailing, onChanged: (value) => controller.changeIsSyncFollows(), ), ), AppStyle.divider, Obx( () => CheckboxListTile( secondary: const Icon(Icons.history), title: const Text("同步播放历史记录"), value: controller.isSyncHistories.value, controlAffinity: ListTileControlAffinity.trailing, onChanged: (value) => controller.changeIsSyncHistories(), ), ), AppStyle.divider, Obx( () => CheckboxListTile( secondary: const Icon(Remix.shield_keyhole_line), title: const Text("同步屏蔽字"), value: controller.isSyncBlockWord.value, controlAffinity: ListTileControlAffinity.trailing, onChanged: (value) => controller.changeIsSyncBlockWord(), ), ), AppStyle.divider, Obx( () => CheckboxListTile( secondary: const Icon(Remix.account_circle_line), title: const Text("同步哔哩哔哩账号"), value: controller.isSyncBilibiliAccount.value, controlAffinity: ListTileControlAffinity.trailing, onChanged: (value) => controller.changeIsSyncBilibiliAccount(), ), ), AppStyle.divider, ], ), ); } } ================================================ FILE: simple_live_app/lib/modules/sync/remote_sync/webdav/webdav_client.dart ================================================ import 'dart:async'; import 'dart:typed_data'; import 'package:webdav_client/webdav_client.dart'; class DAVClient { late Client client; Completer pingCompleter = Completer(); DAVClient( String webDAVUri, String webDAVUser, String webDAVPassword, ) { client = newClient( webDAVUri, user: webDAVUser, password: webDAVPassword, ); client.setHeaders( { 'accept-charset': 'utf-8', 'Content-Type': 'text/xml', }, ); client.setConnectTimeout(8000); client.setSendTimeout(8000); client.setReceiveTimeout(8000); pingCompleter.complete(_ping()); } Future _ping() async { try { await client.ping(); return true; } catch (_) { return false; } } // 强制统一 get root => "/simple_live_app"; get backupFile => "$root/backup.zip"; backup(Uint8List data) async { await client.mkdir("$root"); await client.write("$backupFile", data); return true; } Future> recovery() async { await client.mkdir("$root"); final data = await client.read(backupFile); return data; } } ================================================ FILE: simple_live_app/lib/modules/sync/sync_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/widgets/settings/settings_card.dart'; class SyncPage extends StatelessWidget { const SyncPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("数据同步"), actions: [ Visibility( visible: GetPlatform.isAndroid || GetPlatform.isIOS, child: TextButton.icon( onPressed: () async { var result = await Get.toNamed(RoutePath.kSyncScan); if (result == null || result.isEmpty) { return; } if (result.length == 5) { Get.toNamed(RoutePath.kRemoteSyncRoom, arguments: result); } else { Get.toNamed(RoutePath.kLocalSync, arguments: result); } }, icon: const Icon(Remix.qr_scan_line), label: const Text("扫一扫"), ), ), ], ), body: ListView( padding: AppStyle.edgeInsetsA12, children: [ Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 0), child: Text( "远程同步", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( children: [ ListTile( title: const Text("创建房间"), leading: const Icon(Remix.home_wifi_line), subtitle: const Text("其他设备可以通过房间号加入"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.toNamed(RoutePath.kRemoteSyncRoom); }, ), AppStyle.divider, ListTile( title: const Text("加入房间"), leading: const Icon(Remix.add_circle_line), subtitle: const Text("加入其他设备创建的房间"), trailing: const Icon(Icons.chevron_right), onTap: () async { var input = await Utils.showEditTextDialog( "", title: "加入房间", hintText: "请输入房间号,不区分大小写", validate: (text) { if (text.isEmpty) { SmartDialog.showToast("房间号不能为空"); return false; } if (text.length != 5) { SmartDialog.showToast("请输入5位房间号"); return false; } return true; }, ); if (input != null && input.isNotEmpty) { Get.toNamed(RoutePath.kRemoteSyncRoom, arguments: input.toUpperCase()); } }, ), AppStyle.divider, ListTile( title: const Text("WebDAV"), leading: const Icon(Icons.cloud_upload_outlined), subtitle: const Text("通过WebDAV同步数据"), trailing: const Icon(Icons.chevron_right), onTap: () { Get.toNamed(RoutePath.kRemoteSyncWebDav); }, ), ], ), ), Padding( padding: AppStyle.edgeInsetsA12.copyWith(top: 24), child: Text( "局域网同步", style: Get.textTheme.titleSmall, ), ), SettingsCard( child: Column( children: [ ListTile( title: const Text("局域网同步"), subtitle: const Text("在局域网内同步数据"), leading: const Icon(Remix.device_line), trailing: const Icon(Icons.chevron_right), onTap: () { Get.toNamed(RoutePath.kLocalSync); }, ), ], ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/requests/custom_log_interceptor.dart ================================================ import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_core/simple_live_core.dart'; class CustomLogInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { options.extra["ts"] = DateTime.now().millisecondsSinceEpoch; super.onRequest(options, handler); } @override void onError(DioException err, ErrorInterceptorHandler handler) { var time = DateTime.now().millisecondsSinceEpoch - err.requestOptions.extra["ts"]; if (!kReleaseMode) { Log.e('''【HTTP请求错误-${err.type}】 耗时:${time}ms ${err.message} Request Method:${err.requestOptions.method} Response Code:${err.response?.statusCode} Request URL:${err.requestOptions.uri} Request Query:${err.requestOptions.queryParameters} Request Data:${err.requestOptions.data} Request Headers:${err.requestOptions.headers} Response Headers:${err.response?.headers.map} Response Data:${err.response?.data}''', err.stackTrace); } else { CoreLog.e('''[HTTP Error] [${err.type}] [Time:${time}ms] ${err.message} Request Method:${err.requestOptions.method} Response Code:${err.response?.statusCode} Request URL:${err.requestOptions.uri} Request Query:${err.requestOptions.queryParameters} Request Data:${err.requestOptions.data} Request Headers:${_maskHeader(err.requestOptions.headers)} Response Headers:${err.response?.headers.map} Response Data:${err.response?.data}''', err.stackTrace); } super.onError(err, handler); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { var time = DateTime.now().millisecondsSinceEpoch - response.requestOptions.extra["ts"]; if (!kReleaseMode) { Log.i( '''【HTTP请求响应】 耗时:${time}ms Request Method:${response.requestOptions.method} Request Code:${response.statusCode} Request URL:${response.requestOptions.uri} Request Query:${response.requestOptions.queryParameters} Request Data:${response.requestOptions.data} Request Headers:${response.requestOptions.headers} Response Headers:${response.headers.map} Response Data:${response.data}''', ); } else { CoreLog.i( "[HTTP Response] [time:${time}ms] [${response.statusCode}] ${response.requestOptions.uri}", ); } super.onResponse(response, handler); } // Header脱敏 String _maskHeader(Map header) { var result = {}; header.forEach((key, value) { var k = key.toLowerCase(); if (k == "cookie" || k == "authorization") { result[key] = "******"; } else { result[key] = value; } }); return result.toString(); } } ================================================ FILE: simple_live_app/lib/requests/http_client.dart ================================================ import 'package:dio/dio.dart'; import 'package:simple_live_app/requests/custom_log_interceptor.dart'; import 'package:simple_live_app/requests/http_error.dart'; class HttpClient { static HttpClient? _httpUtil; static HttpClient get instance { _httpUtil ??= HttpClient(); return _httpUtil!; } late Dio dio; HttpClient() { dio = Dio( BaseOptions( connectTimeout: const Duration(seconds: 20), receiveTimeout: const Duration(seconds: 20), sendTimeout: const Duration(seconds: 20), ), ); dio.interceptors.add(CustomLogInterceptor()); } /// Get请求,返回String /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future getText( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.plain, headers: header, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送GET请求失败"); } } } /// Get请求,返回Map /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future getJson( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.json, headers: header, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送GET请求失败"); } } } /// Get请求,返回Response /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future> get( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.json, headers: header, ), cancelToken: cancel, ); return result; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送GET请求失败"); } } } /// Post请求,返回Map /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [data] 内容 /// * [cancel] 任务取消Token Future postJson( String url, { Map? queryParameters, dynamic data, Map? header, bool formUrlEncoded = false, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; data ??= {}; var result = await dio.post( url, queryParameters: queryParameters, data: data, options: Options( responseType: ResponseType.json, headers: header, contentType: formUrlEncoded ? Headers.formUrlEncodedContentType : null, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送POST请求失败"); } } } /// Head请求,返回Response /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future head( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.head( url, queryParameters: queryParameters, options: Options( headers: header, receiveDataWhenStatusError: true, ), cancelToken: cancel, ); return result; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { return e.response!; } else { throw HttpError("发送HEAD请求失败"); } } } } ================================================ FILE: simple_live_app/lib/requests/http_error.dart ================================================ class HttpError extends Error { /// 错误码 final int statusCode; /// 错误信息 final String message; HttpError( this.message, { this.statusCode = 0, }); @override String toString() { if (statusCode != 0) { return statusCodeToString(statusCode); } return message; } String statusCodeToString(int statusCode) { switch (statusCode) { case 400: return "错误的请求(400)"; case 401: return "无权限访问资源(401)"; case 403: return "无权限访问资源(403)"; case 404: return "服务器找不到请求的资源(404)"; case 500: return "服务器出现错误(500)"; case 502: return "服务器出现错误(502)"; case 503: return "服务器出现错误(503)"; default: return "连接服务器失败,请稍后再试($statusCode)"; } } } ================================================ FILE: simple_live_app/lib/requests/sync_client_request.dart ================================================ import 'package:simple_live_app/models/sync_client_info_model.dart'; import 'package:simple_live_app/requests/http_client.dart'; import 'package:simple_live_app/services/sync_service.dart'; class SyncClientRequest { Future getClientInfo(SyncClinet client) async { var url = "http://${client.address}:${client.port}/info"; var data = await HttpClient.instance.getJson(url); return SyncClientInfoModel.fromJson(data); } Future syncFollow( SyncClinet client, dynamic body, { bool overlay = false, }) async { var url = "http://${client.address}:${client.port}/sync/follow"; var data = await HttpClient.instance.postJson( url, data: body, queryParameters: { 'overlay': overlay ? '1' : '0', }, ); if (data["status"]) { return true; } else { throw data["message"]; } } Future syncTag( SyncClinet client, dynamic body, { bool overlay = false, }) async { var url = "http://${client.address}:${client.port}/sync/tag"; var data = await HttpClient.instance.postJson( url, data: body, queryParameters: { 'overlay': overlay ? '1' : '0', }, ); if (data["status"]) { return true; } else { throw data["message"]; } } Future syncHistory( SyncClinet client, dynamic body, { bool overlay = false, }) async { var url = "http://${client.address}:${client.port}/sync/history"; var data = await HttpClient.instance.postJson( url, data: body, queryParameters: { 'overlay': overlay ? '1' : '0', }, ); if (data["status"]) { return true; } else { throw data["message"]; } } Future syncBlockedWord( SyncClinet client, dynamic body, { bool overlay = false, }) async { var url = "http://${client.address}:${client.port}/sync/blocked_word"; var data = await HttpClient.instance.postJson( url, data: body, queryParameters: { 'overlay': overlay ? '1' : '0', }, ); if (data["status"]) { return true; } else { throw data["message"]; } } Future syncBiliAccount(SyncClinet client, String cookie) async { var url = "http://${client.address}:${client.port}/sync/account/bilibili"; var data = await HttpClient.instance.postJson( url, data: { "cookie": cookie, }, ); if (data["status"]) { return true; } else { throw data["message"]; } } } ================================================ FILE: simple_live_app/lib/routes/app_navigation.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/sync_client_info_model.dart'; import 'package:simple_live_app/routes/route_path.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/sync_service.dart'; import 'package:simple_live_core/simple_live_core.dart'; /// APP页面跳转封装 /// * 需要参数的页面都应使用此类 /// * 如不需要参数,可以使用Get.toNamed class AppNavigator { /// 跳转至分类详情 static void toCategoryDetail( {required Site site, required LiveSubCategory category}) { Get.toNamed(RoutePath.kCategoryDetail, arguments: [site, category]); } /// 跳转至直播间 static void toLiveRoomDetail( {required Site site, required String roomId}) async { if (site.id == Constant.kBiliBili && !BiliBiliAccountService.instance.logined.value && AppSettingsController.instance.bilibiliLoginTip.value) { var result = await Utils.showAlertDialog( "哔哩哔哩需要登录才能观看高清直播,是否前往登录?", title: "登录哔哩哔哩", actions: [ TextButton( onPressed: () { AppSettingsController.instance.setBiliBiliLoginTip(false); Get.back(result: false); }, child: const Text("不再提示"), ), ], ); if (result == true) { await toBiliBiliLogin(); if (!BiliBiliAccountService.instance.logined.value) { SmartDialog.showToast("未完成登录"); } } } Get.toNamed(RoutePath.kLiveRoomDetail, arguments: site, parameters: { "roomId": roomId, }); } /// 跳转至哔哩哔哩登录 static Future toBiliBiliLogin() async { if (Platform.isAndroid || Platform.isIOS) { await Get.toNamed(RoutePath.kBiliBiliWebLogin); } else { await Get.toNamed(RoutePath.kBiliBiliQRLogin); } } /// 跳转至同步设备 static Future toSyncDevice( SyncClinet client, SyncClientInfoModel info) async { await Get.toNamed( RoutePath.kLocalSyncDevice, arguments: { "client": client, "info": info, }, ); } } ================================================ FILE: simple_live_app/lib/routes/app_pages.dart ================================================ // ignore_for_file: prefer_inlined_adds import 'package:get/get.dart'; import 'package:simple_live_app/modules/category/detail/category_detail_controller.dart'; import 'package:simple_live_app/modules/category/detail/category_detail_page.dart'; import 'package:simple_live_app/modules/indexed/indexed_controller.dart'; import 'package:simple_live_app/modules/live_room/live_room_controller.dart'; import 'package:simple_live_app/modules/live_room/live_room_page.dart'; import 'package:simple_live_app/modules/settings/follow_settings_page.dart'; import 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_config_page.dart'; import 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_controller.dart'; import 'package:simple_live_app/modules/sync/remote_sync/webdav/remote_sync_webdav_page.dart'; import 'package:simple_live_app/modules/sync/sync_page.dart'; import 'package:simple_live_app/modules/sync/remote_sync/room/remote_sync_room_controller.dart'; import 'package:simple_live_app/modules/sync/remote_sync/room/remote_sync_room_page.dart'; import 'package:simple_live_app/modules/search/search_controller.dart'; import 'package:simple_live_app/modules/search/search_page.dart'; import 'package:simple_live_app/modules/sync/local_sync/device/sync_device_controller.dart'; import 'package:simple_live_app/modules/sync/local_sync/device/sync_device_page.dart'; import 'package:simple_live_app/modules/sync/local_sync/scan_qr/sync_scan_qr_controller.dart'; import 'package:simple_live_app/modules/sync/local_sync/scan_qr/sync_scan_qr_page.dart'; import 'package:simple_live_app/modules/mine/parse/parse_controller.dart'; import 'package:simple_live_app/modules/mine/parse/parse_page.dart'; import 'package:simple_live_app/modules/sync/local_sync/local_sync_controller.dart'; import 'package:simple_live_app/modules/sync/local_sync/local_sync_page.dart'; import 'package:simple_live_app/modules/mine/account/account_controller.dart'; import 'package:simple_live_app/modules/mine/account/account_page.dart'; import 'package:simple_live_app/modules/mine/account/bilibili/qr_login_controller.dart'; import 'package:simple_live_app/modules/mine/account/bilibili/qr_login_page.dart'; import 'package:simple_live_app/modules/mine/account/bilibili/web_login_controller.dart'; import 'package:simple_live_app/modules/mine/account/bilibili/web_login_page.dart'; import 'package:simple_live_app/modules/settings/appstyle_setting_page.dart'; import 'package:simple_live_app/modules/settings/auto_exit_settings_page.dart'; import 'package:simple_live_app/modules/settings/danmu_settings_page.dart'; import 'package:simple_live_app/modules/settings/danmu_shield/danmu_shield_controller.dart'; import 'package:simple_live_app/modules/settings/danmu_shield/danmu_shield_page.dart'; import 'package:simple_live_app/modules/follow_user/follow_user_controller.dart'; import 'package:simple_live_app/modules/follow_user/follow_user_page.dart'; import 'package:simple_live_app/modules/mine/history/history_controller.dart'; import 'package:simple_live_app/modules/mine/history/history_page.dart'; import 'package:simple_live_app/modules/settings/indexed_settings/indexed_settings_controller.dart'; import 'package:simple_live_app/modules/settings/indexed_settings/indexed_settings_page.dart'; import 'package:simple_live_app/modules/settings/other/other_settings_controller.dart'; import 'package:simple_live_app/modules/settings/other/other_settings_page.dart'; import 'package:simple_live_app/modules/settings/play_settings_page.dart'; import '../modules/indexed/indexed_page.dart'; import 'route_path.dart'; class AppPages { AppPages._(); static final routes = [ // 首页 GetPage( name: RoutePath.kIndex, page: () => const IndexedPage(), bindings: [ BindingsBuilder.put(() => IndexedController()), //BindingsBuilder.put(() => HomeController()), ], ), // 观看记录 GetPage( name: RoutePath.kHistory, page: () => const HistoryPage(), bindings: [ BindingsBuilder.put(() => HistoryController()), ], ), // 关注用户 GetPage( name: RoutePath.kFollowUser, page: () => const FollowUserPage(), bindings: [ BindingsBuilder.put(() => FollowUserController()), ], ), // 搜索 GetPage( name: RoutePath.kSearch, page: () => const SearchPage(), bindings: [ BindingsBuilder.put(() => AppSearchController()), ], ), //分类详情 GetPage( name: RoutePath.kCategoryDetail, page: () => const CategoryDetailPage(), binding: BindingsBuilder.put( () => CategoryDetailController( site: Get.arguments[0], subCategory: Get.arguments[1], ), ), ), //直播间 GetPage( name: RoutePath.kLiveRoomDetail, page: () => const LiveRoomPage(), binding: BindingsBuilder.put( () => LiveRoomController( pSite: Get.arguments, pRoomId: Get.parameters["roomId"] ?? "", ), ), ), //弹幕设置 GetPage( name: RoutePath.kSettingsDanmu, page: () => const DanmuSettingsPage(), ), //外观设置 GetPage( name: RoutePath.kAppstyleSetting, page: () => const AppstyleSettingPage()), //播放设置 GetPage( name: RoutePath.kSettingsPlay, page: () => const PlaySettingsPage(), ), //自动关闭 GetPage( name: RoutePath.kSettingsAutoExit, page: () => const AutoExitSettingsPage(), ), //工具箱 GetPage( name: RoutePath.kTools, page: () => const ParsePage(), bindings: [ BindingsBuilder.put(() => ParseController()), ], ), //关键词屏蔽 GetPage( name: RoutePath.kSettingsDanmuShield, page: () => const DanmuShieldPage(), bindings: [ BindingsBuilder.put(() => DanmuShieldController()), ], ), //主页设置 GetPage( name: RoutePath.kSettingsIndexed, page: () => const IndexedSettingsPage(), bindings: [ BindingsBuilder.put(() => IndexedSettingsController()), ], ), //账号设置 GetPage( name: RoutePath.kSettingsAccount, page: () => const AccountPage(), bindings: [ BindingsBuilder.put(() => AccountController()), ], ), //哔哩哔哩Web登录 GetPage( name: RoutePath.kBiliBiliWebLogin, page: () => const BiliBiliWebLoginPage(), bindings: [ BindingsBuilder.put(() => BiliBiliWebLoginController()), ], ), //哔哩哔哩二维码登录 GetPage( name: RoutePath.kBiliBiliQRLogin, page: () => const BiliBiliQRLoginPage(), bindings: [ BindingsBuilder.put(() => BiliBiliQRLoginController()), ], ), // 数据同步 GetPage( name: RoutePath.kSync, page: () => const SyncPage(), ), // 本地同步 GetPage( name: RoutePath.kLocalSync, page: () => const LocalSyncPage(), bindings: [ BindingsBuilder.put( () => LocalSyncController( Get.arguments ?? "", ), ), ], ), //扫码 GetPage( name: RoutePath.kSyncScan, page: () => const SyncScanQRPage(), bindings: [ BindingsBuilder.put(() => SyncScanQRControlelr()), ], ), //同步设备 GetPage( name: RoutePath.kLocalSyncDevice, page: () => const SyncDevicePage(), bindings: [ BindingsBuilder.put( () => SyncDeviceController( client: Get.arguments['client'], info: Get.arguments['info'], ), ), ], ), //远程同步-房间 GetPage( name: RoutePath.kRemoteSyncRoom, page: () => const RemoteSyncRoomPage(), bindings: [ BindingsBuilder.put( () => RemoteSyncRoomController(Get.arguments ?? ""), ), ], ), //远程同步-WebDAV GetPage( name: RoutePath.kRemoteSyncWebDav, page: () => const RemoteSyncWebDAVPage(), bindings: [ BindingsBuilder.put( () => RemoteSyncWebDAVController(), ), ], ), //远程同步-WebDAVConfig GetPage( name: RoutePath.kRemoteSyncWebDavConfig, page: () => const RemoteSyncWebDAVConfigPage(), ), //其他设置 GetPage( name: RoutePath.kSettingsOther, page: () => const OtherSettingsPage(), bindings: [ BindingsBuilder.put(() => OtherSettingsController()), ], ), //关注设置 GetPage( name: RoutePath.kSettingsFollow, page: () => const FollowSettingsPage(), ), ]; } ================================================ FILE: simple_live_app/lib/routes/route_path.dart ================================================ /// 路由路径 class RoutePath { /// 首页 static const kIndex = "/index"; /// 搜索 static const kSearch = "/search"; /// 分类详情 static const kCategoryDetail = "/category/detail"; /// 直播间 static const kLiveRoomDetail = "/room/detail"; /// 弹幕设置 static const kSettingsDanmu = "/settings/danmu"; /// 定时关闭设置 static const kSettingsAutoExit = "/settings/auto_exit"; /// 直播间设置 static const kSettingsPlay = "/settings/play"; /// 弹幕关键词屏蔽 static const kSettingsDanmuShield = "/settings/danmu/shield"; /// 其他设置 static const kSettingsOther = "/settings/other"; /// 赞助 static const kSponsor = "/sponsor"; /// 历史记录 static const kHistory = "/user/history"; /// 我的关注 static const kFollowUser = "/user/follow"; /// 工具箱 static const kTools = "/other/tools"; /// 主页设置 static const kSettingsIndexed = "/settings/indexed"; /// 外观设置 static const kAppstyleSetting = "/settings/appstyle"; /// 账号管理 static const kSettingsAccount = "/settings/account"; /// 关注设置 static const kSettingsFollow = "/settings/follow"; /// BiliBili Web登录 static const kBiliBiliWebLogin = "/settings/account/bilibili/web_login"; /// BiliBili 二维码登录 static const kBiliBiliQRLogin = "/settings/account/bilibili/qr_login"; /// 数据同步 static const kLocalSync = "/local_sync"; /// 数据同步 static const kSync = "/sync"; /// 扫描 static const kSyncScan = "/sync/scan"; /// 同步设备 static const kLocalSyncDevice = "/sync/device"; /// 远程同步-房间 static const kRemoteSyncRoom = "/remote_sync/room"; /// 远程同步-WebDAV static const kRemoteSyncWebDav = "/remote_sync/webDAV"; /// 远程同步-WebDAVConfig static const kRemoteSyncWebDavConfig = "/remote_sync/webDAVConfig"; /// 测试页面 static const kTest = "/test"; } ================================================ FILE: simple_live_app/lib/services/bilibili_account_service.dart ================================================ import 'dart:io'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/models/account/bilibili_user_info_page.dart'; import 'package:simple_live_app/requests/http_client.dart'; import 'package:simple_live_app/services/local_storage_service.dart'; import 'package:simple_live_core/simple_live_core.dart'; class BiliBiliAccountService extends GetxService { static BiliBiliAccountService get instance => Get.find(); var logined = false.obs; var cookie = ""; var uid = 0; var name = "未登录".obs; @override void onInit() { cookie = LocalStorageService.instance .getValue(LocalStorageService.kBilibiliCookie, ""); logined.value = cookie.isNotEmpty; loadUserInfo(); super.onInit(); } Future loadUserInfo() async { if (cookie.isEmpty) { return; } try { var result = await HttpClient.instance.getJson( "https://api.bilibili.com/x/member/web/account", header: { "Cookie": cookie, }, ); if (result["code"] == 0) { var info = BiliBiliUserInfoModel.fromJson(result["data"]); name.value = info.uname ?? "未登录"; uid = info.mid ?? 0; setSite(); } else { SmartDialog.showToast("哔哩哔哩登录已失效,请重新登录"); logout(); } } catch (e) { SmartDialog.showToast("获取哔哩哔哩用户信息失败,可前往账号管理重试"); } } void setSite() { var site = (Sites.allSites[Constant.kBiliBili]!.liveSite as BiliBiliSite); site.userId = uid; site.cookie = cookie; } void setCookie(String cookie) { this.cookie = cookie; LocalStorageService.instance .setValue(LocalStorageService.kBilibiliCookie, cookie); logined.value = cookie.isNotEmpty; } void logout() async { cookie = ""; uid = 0; name.value = "未登录"; setSite(); LocalStorageService.instance .setValue(LocalStorageService.kBilibiliCookie, ""); logined.value = false; if (Platform.isAndroid || Platform.isIOS) { CookieManager cookieManager = CookieManager.instance(); await cookieManager.deleteAllCookies(); } } } ================================================ FILE: simple_live_app/lib/services/db_service.dart ================================================ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:uuid/uuid.dart'; import 'package:collection/collection.dart'; class DBService extends GetxService { static DBService get instance => Get.find(); late Box historyBox; late Box followBox; late Box tagBox; final Uuid uuid = const Uuid(); Future init() async { historyBox = await Hive.openBox("History"); followBox = await Hive.openBox("FollowUser"); tagBox = await Hive.openBox("FollowUserTag"); } // follow_user_tag 相关逻辑 bool getFollowTagExist(String id) { return tagBox.containsKey(id); } // 删除标签 Future deleteFollowTag(String id) async { await tagBox.delete(id); } FollowUserTag? getFollowTag(String tag) { return tagBox.values.firstWhereOrNull((item) => item.tag == tag); } // 判断标签名称是否重复 bool getFollowTagExistByTag(String tag) { return tagBox.values.any((item) => item.tag == tag); } // 获取标签列表 List getFollowTagList() { return tagBox.values.toList(); } // 修改标签 Future updateFollowTag(FollowUserTag followTag) async { await tagBox.put(followTag.id, followTag); } // 添加标签 Future addFollowTag(String tag) async { // 限制标签唯一且长度不超过8个字符 if (getFollowTagExistByTag(tag) && tag.length > 8) { return getFollowTag(tag)!; } final String uniqueId = uuid.v4(); final followUserTag = FollowUserTag(id: uniqueId, tag: tag, userId: []); await tagBox.put(uniqueId, followUserTag); return followUserTag; } // 调整标签顺序 Future updateFollowTagOrder(List userTagList) async { final Map updatedMap = { for (int i = 0; i < userTagList.length; i++) i: userTagList[i] }; await tagBox.clear(); await tagBox.putAll(updatedMap); } bool getFollowExist(String id) { return followBox.containsKey(id); } List getFollowList() { return followBox.values.toList(); } Future addFollow(FollowUser follow) async { await followBox.put(follow.id, follow); } Future deleteFollow(String id) async { await followBox.delete(id); } History? getHistory(String id) { if (historyBox.containsKey(id)) { return historyBox.get(id); } return null; } Future addOrUpdateHistory(History history) async { await historyBox.put(history.id, history); } List getHistores() { var his = historyBox.values.toList(); his.sort((a, b) => b.updateTime.compareTo(a.updateTime)); return his; } } ================================================ FILE: simple_live_app/lib/services/douyin_account_service.dart ================================================ import 'package:get/get.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/services/local_storage_service.dart'; import 'package:simple_live_core/simple_live_core.dart'; class DouyinAccountService extends GetxService { static DouyinAccountService get instance => Get.find(); var cookie = ""; var hasCookie = false.obs; @override void onInit() { cookie = LocalStorageService.instance .getValue(LocalStorageService.kDouyinCookie, ""); hasCookie.value = cookie.isNotEmpty; setSite(); super.onInit(); } void setSite() { var site = (Sites.allSites[Constant.kDouyin]!.liveSite as DouyinSite); site.cookie = cookie; } void setCookie(String cookie) { this.cookie = cookie; LocalStorageService.instance .setValue(LocalStorageService.kDouyinCookie, cookie); hasCookie.value = cookie.isNotEmpty; setSite(); } void clearCookie() { cookie = ""; LocalStorageService.instance .setValue(LocalStorageService.kDouyinCookie, ""); hasCookie.value = false; setSite(); } } ================================================ FILE: simple_live_app/lib/services/follow_service.dart ================================================ import 'dart:async'; import 'dart:collection'; import 'dart:convert'; import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/services/db_service.dart'; class FollowService extends GetxService { StreamSubscription? subscription; static FollowService get instance => Get.find(); final StreamController _updatedListController = StreamController.broadcast(); Stream get updatedListStream => _updatedListController.stream; /// 关注用户列表 RxList followList = RxList(); /// 直播中的用户列表 RxList liveList = RxList(); /// 未直播的用户列表 RxList notLiveList = RxList(); /// 用户自定义的tag RxList followTagList = RxList(); /// 当前tag的用户列表 RxList curTagFollowList = RxList(); /// 已经更新状态的数量 var updatedCount = 0; /// 是否正在更新 var updating = false.obs; Timer? updateTimer; @override void onInit() { subscription = EventBus.instance.listen(Constant.kUpdateFollow, (p0) { loadData(updateStatus: false); }); initTimer(); super.onInit(); } // 添加标签 Future addFollowUserTag(String tag) async { // 判断待添加tag是否已存在,存在则return if (followTagList.any((item) => item.tag == tag)) { SmartDialog.showToast("标签名重复,修改失败"); return; } FollowUserTag item = await DBService.instance.addFollowTag(tag); followTagList.add(item); } // 删除标签 Future delFollowUserTag(FollowUserTag tag) async { followTagList.remove(tag); await DBService.instance.deleteFollowTag(tag.id); } // 获取用户自定义标签列表 void getAllTagList() { var list = DBService.instance.getFollowTagList(); followTagList.assignAll(list); } // 修改标签 void updateFollowUserTag(FollowUserTag tag) { DBService.instance.updateFollowTag(tag); // 查找并修改 var index = followTagList.indexWhere((oTag) => oTag.id == tag.id); followTagList[index] = tag; } // 根据标签筛选数据 void filterDataByTag(FollowUserTag tag) { curTagFollowList.clear(); // 用一个新的列表来存储需要删除的 userId List toRemove = []; for (var id in tag.userId) { if (followList.any((x) => x.id == id)) { // 找到对应的 followUser 添加到 curTagFollowList curTagFollowList.add(followList.firstWhere((x) => x.id == id)); } else { // 标记要删除的 id toRemove.add(id); } } // 双向确认用户取消关注后标签内是否还有该用户 // 在遍历结束后统一移除不在 followList 中的 id tag.userId.removeWhere((id) => toRemove.contains(id)); // 更新数据库 if (toRemove.isNotEmpty) { DBService.instance.updateFollowTag(tag); } // 标签内排序 curTagFollowList.sort( (a, b) => b.liveStatus.value.compareTo(a.liveStatus.value), ); } // 添加关注 Future addFollow(FollowUser follow) async { await DBService.instance.addFollow(follow); } void initTimer() { if (AppSettingsController.instance.autoUpdateFollowEnable.value) { updateTimer?.cancel(); updateTimer = Timer.periodic( Duration( minutes: AppSettingsController.instance.autoUpdateFollowDuration.value), (timer) { Log.logPrint("Update Follow Timer"); loadData(); }, ); } else { updateTimer?.cancel(); } } Future loadData({bool updateStatus = true}) async { var list = DBService.instance.getFollowList(); getAllTagList(); if (list.isEmpty) { updating.value = false; followList.assignAll(list); return; } followList.assignAll(list); if (updateStatus) { startUpdateStatus(); } } /// 获取最优并发数 /// 根据 CPU 核心数和用户设置自动计算 int getOptimalConcurrency() { var userSetting = AppSettingsController.instance.updateFollowThreadCount.value; // 如果用户设置为 0,则自动根据 CPU 核心数计算 if (userSetting == 0) { var cpuCount = Platform.numberOfProcessors; // 网络 I/O 密集型任务,并发数可以是 CPU 核心数的 2-3 倍 var optimal = (cpuCount * 2.5).round(); // 限制在合理范围内(最少 4,最多 20) return optimal.clamp(4, 20); } return userSetting; } /// 按平台交错排列,避免单一平台阻塞 List interleaveByPlatform(List list) { // 按平台分组 var grouped = >{}; for (var item in list) { grouped.putIfAbsent(item.siteId, () => Queue()).add(item); } // 交错处理 var result = []; while (grouped.values.any((queue) => queue.isNotEmpty)) { for (var queue in grouped.values) { if (queue.isNotEmpty) { result.add(queue.removeFirst()); } } } return result; } void startUpdateStatus() async { updatedCount = 0; updating.value = true; var concurrency = getOptimalConcurrency(); Log.logPrint("开始更新关注状态,并发数: $concurrency,总数: ${followList.length}"); // 按平台交错排列,避免单一平台阻塞 var interleavedList = interleaveByPlatform(followList); // 创建任务队列 var taskQueue = Queue.from(interleavedList); // 工作函数 - 持续从队列中取任务执行 Future worker(int workerId) async { while (taskQueue.isNotEmpty) { var item = taskQueue.removeFirst(); await updateLiveStatus(item); } } // 启动固定数量的并发 worker var workers = []; for (var i = 0; i < concurrency; i++) { workers.add(worker(i)); } await Future.wait(workers); Log.logPrint("关注状态更新完成"); } Future updateLiveStatus(FollowUser item) async { try { var site = Sites.allSites[item.siteId]!; // 先只查状态 var isLiving = await site.liveSite.getLiveStatus(roomId: item.roomId); item.liveStatus.value = isLiving ? 2 : 1; if (item.liveStatus.value == 2) { // 只有正在直播时才查详细信息 var detail = await site.liveSite.getRoomDetail(roomId: item.roomId); item.liveStartTime = detail.showTime; } else { item.liveStartTime = null; } } catch (e) { Log.logPrint(e); item.liveStatus.value = 0; item.liveStartTime = null; } finally { updatedCount++; if (updatedCount >= followList.length) { filterData(); updating.value = false; } } } void filterData() { followList.sort((a, b) => b.liveStatus.value.compareTo(a.liveStatus.value)); liveList.assignAll(followList.where((x) => x.liveStatus.value == 2)); notLiveList.assignAll(followList.where((x) => x.liveStatus.value == 1)); _updatedListController.add(0); } void exportFile() async { if (followList.isEmpty) { SmartDialog.showToast("列表为空"); return; } try { var status = await Utils.checkStorgePermission(); if (!status) { SmartDialog.showToast("无权限"); return; } var dir = ""; if (Platform.isIOS) { dir = (await getApplicationDocumentsDirectory()).path; } else { dir = await FilePicker.platform.getDirectoryPath() ?? ""; } if (dir.isEmpty) { return; } var jsonFile = File( '$dir/SimpleLive_${DateTime.now().millisecondsSinceEpoch ~/ 1000}.json'); var jsonText = generateJson(); await jsonFile.writeAsString(jsonText); SmartDialog.showToast("已导出关注列表"); } catch (e) { Log.logPrint(e); SmartDialog.showToast("导出失败:$e"); } } void inputFile() async { try { var status = await Utils.checkStorgePermission(); if (!status) { SmartDialog.showToast("无权限"); return; } var file = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['json'], ); if (file == null) { return; } var jsonFile = File(file.files.single.path!); await inputJson(await jsonFile.readAsString()); SmartDialog.showToast("导入成功"); } catch (e) { Log.logPrint(e); SmartDialog.showToast("导入失败:$e"); } finally { loadData(); } } void exportText() { if (followList.isEmpty) { SmartDialog.showToast("列表为空"); return; } var content = generateJson(); Get.dialog( AlertDialog( title: const Text("导出为文本"), content: TextField( controller: TextEditingController(text: content), decoration: const InputDecoration( border: OutlineInputBorder(), ), minLines: 5, maxLines: 8, ), actions: [ TextButton( onPressed: () { Get.back(); }, child: const Text("关闭"), ), TextButton( onPressed: () { Utils.copyToClipboard(content); Get.back(); }, child: const Text("复制"), ), ], ), ); } void inputText() async { final TextEditingController textController = TextEditingController(); await Get.dialog( AlertDialog( title: const Text("从文本导入"), content: TextField( controller: textController, decoration: const InputDecoration( border: OutlineInputBorder(), hintText: "请输入内容", ), minLines: 5, maxLines: 8, ), actions: [ TextButton( onPressed: () { Get.back(); }, child: const Text("关闭"), ), TextButton( onPressed: () async { var content = await Utils.getClipboard(); if (content != null) { textController.text = content; } }, child: const Text("粘贴"), ), TextButton( onPressed: () async { if (textController.text.isEmpty) { SmartDialog.showToast("内容为空"); return; } try { await inputJson(textController.text); SmartDialog.showToast("导入成功"); Get.back(); loadData(); } catch (e) { SmartDialog.showToast("导入失败,请检查内容是否正确"); } }, child: const Text("导入"), ), ], ), ); } String generateJson() { var data = followList .map( (item) => { "siteId": item.siteId, "id": item.id, "roomId": item.roomId, "userName": item.userName, "face": item.face, "addTime": item.addTime.toString(), "tag": item.tag }, ) .toList(); return jsonEncode(data); } Future inputJson(String content) async { var data = jsonDecode(content); for (var item in data) { var follow = FollowUser.fromJson(item); // 导入关注列表同时导入标签列表 此方法可优化为所有导入逻辑 if (follow.tag != "全部") { // logic: 尝试添加,存在则返回已存在的对象 var tag = await DBService.instance.addFollowTag(follow.tag); // 更新tag tag.userId.addIf(!tag.userId.contains(follow.id), follow.id); await DBService.instance.updateFollowTag(tag); } await DBService.instance.addFollow(follow); } } @override void onClose() { updateTimer?.cancel(); subscription?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_app/lib/services/local_storage_service.dart ================================================ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:simple_live_app/app/log.dart'; class LocalStorageService extends GetxService { static LocalStorageService get instance => Get.find(); /// 首次运行 static const String kFirstRun = "FirstRun"; /// 缩放模式 static const String kPlayerScaleMode = "ScaleMode"; /// 网站排序 static const String kSiteSort = "SiteSort"; /// 首页排序 static const String kHomeSort = "HomeSort"; /// 显示模式 /// * [0] 跟随系统 /// * [1] 浅色模式 /// * [2] 深色模式 static const String kThemeMode = "ThemeMode"; /// DEBUG模式 static const String kDebugModeKey = "DebugMode"; /// 弹幕大小 static const String kDanmuSize = "DanmuSize"; /// 弹幕速度 static const String kDanmuSpeed = "DanmuSpeed"; /// 弹幕区域 static const String kDanmuArea = "DanmuArea"; /// 弹幕透明度 static const String kDanmuOpacity = "DanmuOpacity"; /// 弹幕描边大小 static const String kDanmuStrokeWidth = "DanmuStrokeWidth"; /// 弹幕-屏蔽滚动 static const String kDanmuHideScroll = "DanmuHideScroll"; /// 弹幕-屏蔽底部 static const String kDanmuHideBottom = "DanmuHideBottom"; /// 弹幕-屏蔽顶部 static const String kDanmuHideTop = "DanmuHideTop"; /// 弹幕-顶部边距 static const String kDanmuTopMargin = "DanmuTopMargin"; /// 弹幕-底部边距 static const String kDanmuBottomMargin = "DanmuBottomMargin"; /// 弹幕开启 static const String kDanmuEnable = "DanmuEnable"; /// 弹幕字重 static const String kDanmuFontWeight = "DanmuFontWeight"; /// 硬件解码 static const String kHardwareDecode = "HardwareDecode"; /// 聊天区文字大小 static const String kChatTextSize = "ChatTextSize"; /// 聊天区间隔 static const String kChatTextGap = "ChatTextGap"; /// 聊天区-气泡样式 static const String kChatBubbleStyle = "ChatBubbleStyle"; /// 播放清晰度,0=低,1=中,2=高 static const String kQualityLevel = "QualityLevel"; /// 蜂窝网络下播放清晰度,0=低,1=中,2=高 static const String kQualityLevelCellular = "QualityLevelCellular"; /// 开启定时关闭 static const String kAutoExitEnable = "AutoExitEnable"; /// 定时关闭时间(分钟) static const String kAutoExitDuration = "AutoExitDuration"; /// 房间内定时关闭时间(分钟) /// 需要一个不同的 key,因为用户在房间内设置的倒计时和全局的可能不同。 static const String kRoomAutoExitDuration = "RoomAutoExitDuration"; /// 播放器兼容模式 static const String kPlayerCompatMode = "PlayerCompatMode"; /// 播放器后台自动暂停 static const String kPlayerAutoPause = "PlayerAutoPause"; /// 播放器缓冲区大小 static const String kPlayerBufferSize = "PlayerBufferSize"; /// 播放器强制使用HTTPS static const String kPlayerForceHttps = "PlayerForceHttps"; /// 自动全屏 static const String kAutoFullScreen = "AutoFullScreen"; /// 显示SC static const String kPlayerShowSuperChat = "PlayerShowSuperChat"; /// 播放器音量 static const String kPlayerVolume = "PlayerVolume"; /// 小窗隐藏弹幕 static const String kPIPHideDanmu = "PIPHideDanmu"; /// 哔哩哔哩cookie static const String kBilibiliCookie = "BilibiliCookie"; /// 抖音cookie static const String kDouyinCookie = "DouyinCookie"; ///主题色 static const String kStyleColor = "kStyleColor"; ///动态取色 static const String kIsDynamic = "kIsDynamic"; /// 提示哔哩哔哩登录 static const String kBilibiliLoginTip = "BilibiliLoginTip"; /// 日志记录 static const String kLogEnable = "LogEnable"; /// 开启自定义播放器视频输出 static const String kCustomPlayerOutput = "CustomPlayerOutput"; /// 视频输出驱动 static const String kVideoOutputDriver = "VideoOutputDriver"; /// 视频硬件解码器 static const String kVideoHardwareDecoder = "VideoHardwareDecoder"; /// 音频输出驱动 static const String kAudioOutputDriver = "AudioOutputDriver"; /// 开启自动更新关注 static const String kAutoUpdateFollowEnable = "AutoUpdateFollowEnable"; /// 定时自动更新关注间隔(分钟) static const String kUpdateFollowDuration = "AutoUpdateFollowDuration"; /// 开启多线程更新关注 static const String kUpdateFollowThreadCount = "UpdateFollowThreadCount"; /// WebDAV_服务器地址 static const String kWebDAVUri = "WebDAVUri"; /// WebDAV_登录账号 static const String kWebDAVUser = "WebDAVUser"; /// WebDAV_登录密码 static const String kWebDAVPassword = "kWebDAVPassword"; /// WebDAV_最后一次上传时间 static const String kWebDAVLastUploadTime = "kWebDAVLastUploadTime"; /// WebDAV_最后一次备份时间 static const String kWebDAVLastRecoverTime = "kWebDAVLastRecoverTime"; late Box settingsBox; late Box shieldBox; Future init() async { settingsBox = await Hive.openBox( "LocalStorage", ); shieldBox = await Hive.openBox( "DanmuShield", ); } T getValue(dynamic key, T defaultValue) { try { var value = settingsBox.get(key, defaultValue: defaultValue) as T; Log.d("Get LocalStorage:$key\r\n$value"); return value; } catch (e) { Log.logPrint(e); return defaultValue; } } Future setValue(dynamic key, T value) async { Log.d("Set LocalStorage:$key\r\n$value"); return await settingsBox.put(key, value); } Future removeValue(dynamic key) async { Log.d("Remove LocalStorage:$key"); return await settingsBox.delete(key); } } ================================================ FILE: simple_live_app/lib/services/signalr_service.dart ================================================ import 'dart:async'; import 'dart:io'; import 'package:signalr_netcore/signalr_client.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; enum SignalRConnectionState { connecting, connected, disconnected, } class SignalRService { static const String kUrl = "https://sync1.nsapps.cn/sync"; SignalRConnectionState state = SignalRConnectionState.connecting; final _stateStreamController = StreamController.broadcast(); Stream get stateStream => _stateStreamController.stream; final _onFavoriteStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onFavoriteStream => _onFavoriteStreamController.stream; final _onHistoryStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onHistoryStream => _onHistoryStreamController.stream; final _onShieldWordStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onShieldWordStream => _onShieldWordStreamController.stream; final _onBiliAccountStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onBiliAccountStream => _onBiliAccountStreamController.stream; final _onRoomDestroyedStreamController = StreamController.broadcast(); Stream get onRoomDestroyedStream => _onRoomDestroyedStreamController.stream; final _onRoomUserUpdatedStreamController = StreamController>.broadcast(); Stream> get onRoomUserUpdatedStream => _onRoomUserUpdatedStreamController.stream; HubConnection? hubConnection; Future connect() async { hubConnection = HubConnectionBuilder().withUrl(kUrl).build(); hubConnection!.onclose(({Exception? error}) { state = SignalRConnectionState.disconnected; _stateStreamController.add(state); }); hubConnection!.onreconnected(({String? connectionId}) { Log.d("reconnected: $connectionId"); state = SignalRConnectionState.connected; _stateStreamController.add(state); }); await hubConnection!.start(); state = SignalRConnectionState.connected; _stateStreamController.add(state); _listen(); } void _listen() { hubConnection?.on("onFavoriteReceived", (args) { _onFavoriteStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onHistoryReceived", (args) { _onHistoryStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onShieldWordReceived", (args) { _onShieldWordStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onBiliAccountReceived", (args) { _onBiliAccountStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onRoomDestroyed", (args) { _onRoomDestroyedStreamController.add(args![0].toString()); }); hubConnection?.on("onUserUpdated", (args) { var list = (args![0] as List).map((e) => RoomUser.fromObject(e)).toList(); _onRoomUserUpdatedStreamController.add(list); }); } Future disconnect() async { await hubConnection?.stop(); state = SignalRConnectionState.disconnected; _stateStreamController.add(state); } Future> createRoom() async { if (state != SignalRConnectionState.connected) { throw Exception("not connected"); } String app = "Simple Live"; String platform = Platform.operatingSystem; String version = Utils.packageInfo.version; var resp = await hubConnection ?.invoke("CreateRoom", args: [app, platform, version]); return Resp.fromObject(resp); } Future joinRoom(String roomId) async { if (state != SignalRConnectionState.connected) { throw Exception("not connected"); } String app = "Simple Live"; String platform = Platform.operatingSystem; String version = Utils.packageInfo.version; var resp = await hubConnection ?.invoke("JoinRoom", args: [roomId, app, platform, version]); return Resp.fromObject(resp); } Future sendContent({ required String roomName, required String action, required bool overlay, required String content, }) async { if (state != SignalRConnectionState.connected) { throw Exception("not connected"); } var resp = await hubConnection?.invoke(action, args: [roomName, overlay, content]); return Resp.fromObject(resp); } void dispose() { _stateStreamController.close(); _onFavoriteStreamController.close(); _onHistoryStreamController.close(); _onShieldWordStreamController.close(); _onBiliAccountStreamController.close(); _onRoomDestroyedStreamController.close(); _onRoomUserUpdatedStreamController.close(); hubConnection?.stop(); } } class Resp { final bool isSuccess; final String message; final T? data; Resp(this.isSuccess, this.message, this.data); factory Resp.fromJson(Map json) { return Resp( json['isSuccess'], json['message'] ?? "", json['data'], ); } factory Resp.fromObject(Object? obj) { if (obj is Map) { return Resp.fromJson(obj); } return Resp(false, "unknown", null); } } class RoomUser { final String connectionId; final String shortId; final String platform; final String version; final String app; final bool? isCreator; RoomUser({ required this.connectionId, required this.shortId, required this.platform, required this.version, required this.app, this.isCreator = false, }); factory RoomUser.fromJson(Map json) { return RoomUser( connectionId: json['connectionId'], shortId: json['shortId'], platform: json['platform'], version: json['version'], app: json['app'], isCreator: json['isCreator'], ); } factory RoomUser.fromObject(Object? obj) { if (obj is Map) { return RoomUser.fromJson(obj); } return RoomUser( connectionId: "", shortId: "", platform: "", version: "", app: "", ); } } ================================================ FILE: simple_live_app/lib/services/sync_service.dart ================================================ import 'dart:convert'; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:simple_live_app/app/constant.dart'; import 'package:simple_live_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_app/app/event_bus.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/models/db/follow_user_tag.dart'; import 'package:simple_live_app/models/db/history.dart'; import 'package:simple_live_app/services/bilibili_account_service.dart'; import 'package:simple_live_app/services/db_service.dart'; import 'package:udp/udp.dart'; import 'package:shelf/shelf.dart' as shelf; import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf_router/shelf_router.dart'; import 'package:uuid/uuid.dart'; class SyncService extends GetxService { static SyncService get instance => Get.find(); UDP? udp; RxList scanClients = [].obs; static const int udpPort = 23235; static const int httpPort = 23234; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); NetworkInfo networkInfo = NetworkInfo(); HttpServer? server; var ipAddress = "".obs; var httpRunning = false.obs; var httpErrorMsg = "".obs; var deviceId = ""; @override void onInit() { Log.d('TVService init'); deviceId = (const Uuid().v4()).split('-').first; listenUDP(); initServer(); super.onInit(); } /// 监听其他端UDP广播的回复 void listenUDP() async { udp = await UDP.bind(Endpoint.any(port: const Port(udpPort))); udp!.asStream().listen(listenUdp); } void listenUdp(Datagram? datagram) { var str = String.fromCharCodes(datagram!.data); Log.i("Received: $str from ${datagram.address}:${datagram.port}"); if (str.startsWith('{') && str.endsWith('}')) { var data = json.decode(str); //如果是自己的广播,就不处理 if (data['id'] == deviceId) { return; } //处理Hello的广播 if (data["type"] == "hello") { //如果http服务已经启动,就回复自己的信息 if (httpRunning.value) { sendInfo(); } return; } // 处理其他端的广播 // 地址直接从datagram中获取,能收到回复说明地址是可以连通的 var address = datagram.address.address; //检查是否已经存在 var index = scanClients.indexWhere((element) => element.address == address); if (index == -1) { scanClients.add( SyncClinet( id: data['id'], name: data['name'], address: address, port: httpPort, type: data['type'], ), ); } } } /// 发送UDP广播至其他端 void sendHello() async { await udp!.send( json.encode({ "id": deviceId, "type": "hello", }).codeUnits, Endpoint.broadcast( port: const Port(udpPort), ), ); Log.i("send udp: hello"); } /// UDP广播自身信息 void sendInfo() async { //var ip = await getLocalIP(); var name = await getDeviceName(); var data = { "id": deviceId, "type": Platform.operatingSystem, //'version': Utils.packageInfo.version, "name": name, //"address": ip, //"port": httpPort, }; await udp!.send( json.encode(data).codeUnits, Endpoint.broadcast( port: const Port(udpPort), ), ); Log.i("send udp info: $data"); } Future getDeviceName() async { var name = "SimpleLive-${Platform.operatingSystem}"; if (Platform.isAndroid) { var info = await deviceInfo.androidInfo; name = info.model; } else if (Platform.isIOS) { var info = await deviceInfo.iosInfo; name = info.name; } else if (Platform.isMacOS) { var info = await deviceInfo.macOsInfo; name = info.computerName; } else if (Platform.isLinux) { var info = await deviceInfo.linuxInfo; name = info.name; } else if (Platform.isWindows) { var info = await deviceInfo.windowsInfo; name = info.userName; } return name; } void refreshClients() { scanClients.clear(); sendHello(); } /// 读取本地IP /// - 如果是wifi,直接获取wifi的IP /// - 如果是有线,获取所有的IP,找到全部的IP Future getLocalIP() async { String? ip = ""; try { ip = await networkInfo.getWifiIP(); } catch (e) { Log.logPrint(e); } try { if (ip == null || ip.isEmpty) { var interfaces = await NetworkInterface.list(); var ipList = []; for (var interface in interfaces) { for (var addr in interface.addresses) { if (addr.type.name == 'IPv4' && !addr.address.startsWith('127') && !addr.isMulticast && !addr.isLoopback) { ipList.add(addr.address); break; } } } ip = ipList.join(';'); } } catch (e) { Log.logPrint(e); } return ip ?? ""; } /// 初始化HTTP服务 void initServer() async { try { var serverRouter = Router(); serverRouter.get('/', _helloRequest); serverRouter.get('/info', _infoRequest); serverRouter.post('/sync/follow', _syncFollowUserReuqest); serverRouter.post('/sync/tag', _syncFollowUserTagRequest); serverRouter.post('/sync/history', _syncHistoryReuqest); serverRouter.post('/sync/blocked_word', _syncBlockedWordReuqest); serverRouter.post('/sync/account/bilibili', _syncBiliAccountReuqest); var server = await shelf_io.serve( serverRouter, InternetAddress.anyIPv4, httpPort, ); // Enable content compression server.autoCompress = true; httpRunning.value = true; var ip = await getLocalIP(); ipAddress.value = ip; Log.d('Serving at http://$ip:${server.port}'); } catch (e) { httpErrorMsg.value = e.toString(); Log.logPrint(e); } } /// 测试服务能否正常访问 shelf.Response _helloRequest(shelf.Request request) { return toJsonResponse({ 'status': true, 'message': 'http server is running...', "version": 'SimpeLive ${Platform.operatingSystem} v${Utils.packageInfo.version}', }); } /// 发送自己的信息 Future _infoRequest(shelf.Request request) async { var name = await getDeviceName(); return toJsonResponse({ "id": deviceId, 'type': Platform.operatingSystem, 'name': name, 'version': Utils.packageInfo.version, 'address': ipAddress.value, 'port': httpPort, }); } /// 同步关注用户列表 Future _syncFollowUserReuqest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncFollowUserReuqest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { await DBService.instance.followBox.clear(); } for (var item in jsonBody) { var user = FollowUser.fromJson(item); await DBService.instance.followBox.put(user.id, user); } SmartDialog.showToast('已同步关注用户列表'); EventBus.instance.emit(Constant.kUpdateFollow, 0); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步标签列表 Future _syncFollowUserTagRequest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncFollowUserTagRequest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { await DBService.instance.tagBox.clear(); } for (var item in jsonBody) { var tag = FollowUserTag.fromJson(item); await DBService.instance.tagBox.put(tag.id, tag); } SmartDialog.showToast('已同步标签列表'); EventBus.instance.emit(Constant.kUpdateFollow, 0); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步观看记录 Future _syncHistoryReuqest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncFollowUserReuqest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { await DBService.instance.historyBox.clear(); } for (var item in jsonBody) { var history = History.fromJson(item); if (DBService.instance.historyBox.containsKey(history.id)) { var old = DBService.instance.historyBox.get(history.id); //如果本地的更新时间比较新,就不更新 if (old!.updateTime.isAfter(history.updateTime)) { continue; } } await DBService.instance.addOrUpdateHistory(history); } SmartDialog.showToast('已同步观看记录'); EventBus.instance.emit(Constant.kUpdateHistory, 0); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步弹幕屏蔽词 Future _syncBlockedWordReuqest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncBlockedWordReuqest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { AppSettingsController.instance.clearShieldList(); } for (var keyword in jsonBody) { AppSettingsController.instance.addShieldList(keyword.trim()); } SmartDialog.showToast('已同步弹幕屏蔽词'); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步哔哩哔哩账号 Future _syncBiliAccountReuqest(shelf.Request request) async { try { var body = await request.readAsString(); Log.d('_syncBiliAccountReuqest: $body'); var jsonBody = json.decode(body); var cookie = jsonBody['cookie']; BiliBiliAccountService.instance.setCookie(cookie); BiliBiliAccountService.instance.loadUserInfo(); SmartDialog.showToast('已同步哔哩哔哩账号'); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } shelf.Response toJsonResponse(Map data) { return shelf.Response.ok( json.encode(data), headers: { 'Content-Type': 'application/json', }, encoding: Encoding.getByName('utf-8'), ); } @override void onClose() { Log.d('SyncService close'); udp?.close(); server?.close(force: true); super.onClose(); } } class SyncClinet { final String id; final String name; final String address; final int port; final String type; SyncClinet({ required this.id, required this.name, required this.address, required this.port, required this.type, }); } ================================================ FILE: simple_live_app/lib/widgets/desktop_refresh_button.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; class DesktopRefreshButton extends StatelessWidget { final bool refreshing; final Function()? onPressed; const DesktopRefreshButton( {required this.refreshing, this.onPressed, super.key}); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: Theme.of(context).cardColor, borderRadius: AppStyle.radius48, boxShadow: [ BoxShadow( color: Colors.grey.withAlpha(50), blurRadius: 4, ), ], ), width: 40, height: 40, child: refreshing ? const Center( child: SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, ), ), ) : IconButton( onPressed: onPressed, icon: const Icon(Icons.refresh), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/filter_button.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; class FilterButton extends StatelessWidget { final bool selected; final String text; final Function()? onTap; const FilterButton({ this.selected = false, required this.text, this.onTap, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return InkWell( borderRadius: AppStyle.radius24, onTap: onTap, child: Container( padding: AppStyle.edgeInsetsH12.copyWith(top: 4, bottom: 4), decoration: BoxDecoration( border: Border.all( color: selected ? Theme.of(context).textTheme.bodyMedium!.color! : Colors.grey), borderRadius: AppStyle.radius24, ), child: Text( text, style: selected ? Theme.of(context).textTheme.bodyMedium : Theme.of(context).textTheme.bodyMedium!.copyWith( color: Colors.grey, ), ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/follow_user_item.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/log.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/models/db/follow_user.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'dart:ui' as ui; class FollowUserItem extends StatelessWidget { final FollowUser item; final Function()? onRemove; final Function()? onTap; final Function()? onLongPress; final bool playing; const FollowUserItem({ required this.item, this.onRemove, this.onTap, this.onLongPress, this.playing = false, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { var site = Sites.allSites[item.siteId]!; return ListTile( contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 4), leading: NetImage( item.face, width: 48, height: 48, borderRadius: 24, ), title: Text.rich( TextSpan( text: item.userName, children: [ WidgetSpan( alignment: ui.PlaceholderAlignment.middle, child: Obx( () => Offstage( offstage: item.liveStatus.value == 0, child: Row( mainAxisSize: MainAxisSize.min, children: [ AppStyle.hGap12, Container( width: 8, height: 8, decoration: BoxDecoration( color: item.liveStatus.value == 2 ? Colors.green : Colors.grey, borderRadius: AppStyle.radius12, ), ), AppStyle.hGap4, Text( getStatus(item.liveStatus.value), style: TextStyle( fontSize: 12, fontWeight: FontWeight.normal, color: item.liveStatus.value == 2 ? null : Colors.grey, ), ), ], ), ), ), ), ], ), ), subtitle: Wrap( runSpacing: 1.0, children: [ Image.asset( site.logo, width: 20, ), AppStyle.hGap4, Text( site.name, style: const TextStyle( fontSize: 12, color: Colors.grey, ), overflow: TextOverflow.ellipsis, ), if (playing) Padding( padding: AppStyle.edgeInsetsL8, child: Text( "正在观看", style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.bold, ), ), ) else if (item.liveStatus.value == 2 && item.liveStartTime != null) Padding( padding: AppStyle.edgeInsetsL8, child: Text( '开播了${formatLiveDuration(item.liveStartTime)}', style: const TextStyle( fontSize: 12, color: Colors.grey, ), ), ), ], ), trailing: playing ? const SizedBox( width: 64, child: Center( child: Icon( Icons.play_arrow, ), ), ) : (onRemove == null ? null : IconButton( onPressed: () { onRemove?.call(); }, icon: const Icon(Remix.dislike_line), )), onTap: onTap, onLongPress: onLongPress, ); } String getStatus(int status) { if (status == 0) { return "读取中"; } else if (status == 1) { return "未开播"; } else { return "直播中"; } } String formatLiveDuration(String? startTimeStampString) { if (startTimeStampString == null || startTimeStampString.isEmpty || startTimeStampString == "0") { return ""; } try { int startTimeStamp = int.parse(startTimeStampString); int currentTimeStamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; int durationInSeconds = currentTimeStamp - startTimeStamp; int hours = durationInSeconds ~/ 3600; int minutes = (durationInSeconds % 3600) ~/ 60; String hourText = hours > 0 ? '$hours小时' : ''; String minuteText = minutes > 0 ? '$minutes分钟' : ''; if (hours == 0 && minutes == 0) { return "不足1分钟"; } return '$hourText$minuteText'; } catch (e) { Log.logPrint('格式化开播时长出错: $e'); return "--小时--分钟"; } } } ================================================ FILE: simple_live_app/lib/widgets/keep_alive_wrapper.dart ================================================ import 'package:flutter/material.dart'; class KeepAliveWrapper extends StatefulWidget { final Widget child; const KeepAliveWrapper({Key? key, required this.child}) : super(key: key); @override State createState() => _KeepAliveWrapperState(); } class _KeepAliveWrapperState extends State with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { super.build(context); return widget.child; } @override bool get wantKeepAlive => true; } ================================================ FILE: simple_live_app/lib/widgets/live_room_card.dart ================================================ import 'package:flutter/material.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/sites.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/routes/app_navigation.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'package:simple_live_app/widgets/shadow_card.dart'; import 'package:simple_live_core/simple_live_core.dart'; class LiveRoomCard extends StatelessWidget { final Site site; final LiveRoomItem item; const LiveRoomCard(this.site, this.item, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ShadowCard( onTap: () { AppNavigator.toLiveRoomDetail(site: site, roomId: item.roomId); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Stack( children: [ ClipRRect( borderRadius: const BorderRadius.only( topLeft: Radius.circular(8), topRight: Radius.circular(8), ), child: NetImage( item.cover, fit: BoxFit.cover, height: 110, width: double.infinity, ), ), Positioned( right: 0, left: 0, bottom: 0, child: Container( padding: const EdgeInsets.symmetric( horizontal: 4, vertical: 8, ), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [ Colors.black87, Colors.transparent, ], ), ), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const Icon( Remix.fire_fill, color: Colors.white, size: 14, ), AppStyle.hGap4, Text( Utils.onlineToString(item.online), style: const TextStyle( fontSize: 12, color: Colors.white, ), ) ], ), ), ), ], ), Padding( padding: AppStyle.edgeInsetsA8.copyWith(bottom: 4), child: Text( item.title, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), Padding( padding: AppStyle.edgeInsetsH8.copyWith(bottom: 8), child: Text( item.userName, maxLines: 1, style: const TextStyle( height: 1.4, fontSize: 12, color: Colors.grey), ), ) ], ), ); } } ================================================ FILE: simple_live_app/lib/widgets/net_image.dart ================================================ import 'package:extended_image/extended_image.dart'; import 'package:flutter/material.dart'; class NetImage extends StatelessWidget { final String picUrl; final double? width; final double? height; final BoxFit? fit; final double borderRadius; const NetImage(this.picUrl, {this.width, this.height, this.fit = BoxFit.cover, this.borderRadius = 0, Key? key}) : super(key: key); @override Widget build(BuildContext context) { if (picUrl.isEmpty) { return Image.asset( 'assets/images/logo.png', width: width, height: height, ); } var pic = picUrl; if (pic.startsWith("//")) { pic = 'https:$pic'; } return ClipRRect( borderRadius: BorderRadius.circular(borderRadius), child: ExtendedImage.network( pic, fit: fit, height: height, width: width, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(borderRadius), loadStateChanged: (e) { if (e.extendedImageLoadState == LoadState.loading) { return const Icon( Icons.image, color: Colors.grey, size: 24, ); } if (e.extendedImageLoadState == LoadState.failed) { return const Icon( Icons.broken_image, color: Colors.grey, size: 24, ); } return null; }, ), ); } } ================================================ FILE: simple_live_app/lib/widgets/none_border_circular_textfield.dart ================================================ import 'package:flutter/material.dart'; class NoneBorderCircularTextField extends StatelessWidget { final TextEditingController editingController; final String? hintText; final String? helperText; final String? labelText; final String? errorText; final Widget? prefixIcon; final bool obscureText; final VoidCallback? onEditingComplete; final ValueChanged? onChanged; final VoidCallback? onTap; final TextAlign textAlign; final Widget? trailing; final TextInputType? inputType; final int? maxLines; final bool autoFocus; final FocusNode? focusNode; final bool? enable; final bool readOnly; final bool needPadding; const NoneBorderCircularTextField({ Key? key, required this.editingController, this.hintText, this.helperText, this.labelText, this.errorText, this.prefixIcon, this.textAlign = TextAlign.start, this.obscureText = false, this.maxLines = 1, this.onEditingComplete, this.trailing, this.autoFocus = false, this.focusNode, this.inputType, this.onChanged, this.onTap, this.enable, this.readOnly = false, this.needPadding = true, }) : super(key: key); @override Widget build(BuildContext context) { TextField common = TextField( enabled: enable, readOnly: readOnly, decoration: InputDecoration( prefixIcon: prefixIcon, hintText: hintText, filled: true, contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 12), suffix: trailing, helperText: helperText, helperMaxLines: 3, border: const OutlineInputBorder( borderSide: BorderSide.none, borderRadius: BorderRadius.all(Radius.circular(8.0)), ), labelText: labelText, errorText: errorText, errorMaxLines: 3, ), textAlign: textAlign, autofocus: autoFocus, keyboardType: inputType, maxLines: maxLines, controller: editingController, obscureText: obscureText, onEditingComplete: onEditingComplete, onChanged: onChanged, onTap: onTap, focusNode: focusNode, ); if (needPadding) { return Padding( padding: const EdgeInsets.only( top: 10, bottom: 10, ), child: common, ); } else { return common; } } } ================================================ FILE: simple_live_app/lib/widgets/page_grid_view.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/widgets/status/app_empty_widget.dart'; import 'package:simple_live_app/widgets/status/app_error_widget.dart'; import 'package:simple_live_app/widgets/status/app_loadding_widget.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; class PageGridView extends StatelessWidget { final BasePageController pageController; final IndexedWidgetBuilder itemBuilder; final EdgeInsets? padding; final bool firstRefresh; final Function()? onLoginSuccess; final bool showPageLoadding; final double crossAxisSpacing, mainAxisSpacing; final int crossAxisCount; final bool showPCRefreshButton; const PageGridView({ required this.itemBuilder, required this.pageController, this.padding, this.firstRefresh = false, this.showPageLoadding = false, this.onLoginSuccess, this.crossAxisSpacing = 0.0, this.mainAxisSpacing = 0.0, this.showPCRefreshButton = true, required this.crossAxisCount, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Obx( () => Stack( children: [ EasyRefresh( header: MaterialHeader( completeDuration: const Duration(milliseconds: 400), ), footer: MaterialFooter( completeDuration: const Duration(milliseconds: 400), ), scrollController: pageController.scrollController, controller: pageController.easyRefreshController, firstRefresh: firstRefresh, onLoad: pageController.loadData, onRefresh: pageController.refreshData, child: MasonryGridView.count( padding: padding, itemCount: pageController.list.length, itemBuilder: itemBuilder, crossAxisCount: crossAxisCount, crossAxisSpacing: crossAxisSpacing, mainAxisSpacing: mainAxisSpacing, ), ), Positioned( bottom: 0, left: 0, right: 0, child: // 加载更多按钮 Visibility( visible: (Platform.isWindows || Platform.isLinux || Platform.isMacOS) && pageController.canLoadMore.value && !pageController.pageLoadding.value && !pageController.pageEmpty.value, child: Center( child: TextButton( onPressed: pageController.loadData, child: const Text("加载更多"), ), ), ), ), Positioned( bottom: 12, right: 12, child: // 加载更多按钮 Visibility( visible: (Platform.isWindows || Platform.isLinux || Platform.isMacOS) && pageController.canLoadMore.value && !pageController.pageLoadding.value && !pageController.pageEmpty.value && showPCRefreshButton, child: Center( child: IconButton( style: IconButton.styleFrom( backgroundColor: Get.theme.cardColor.withAlpha(200), elevation: 4, ), onPressed: () { pageController.refreshData(); }, icon: const Icon(Icons.refresh), ), ), ), ), Offstage( offstage: !pageController.pageEmpty.value, child: AppEmptyWidget( onRefresh: () => pageController.refreshData(), ), ), Offstage( offstage: !(showPageLoadding && pageController.pageLoadding.value), child: const AppLoaddingWidget(), ), Offstage( offstage: !pageController.pageError.value, child: AppErrorWidget( errorMsg: pageController.errorMsg.value, onRefresh: () => pageController.refreshData(), ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/widgets/page_list_view.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:simple_live_app/app/controller/base_controller.dart'; import 'package:simple_live_app/widgets/status/app_empty_widget.dart'; import 'package:simple_live_app/widgets/status/app_error_widget.dart'; import 'package:simple_live_app/widgets/status/app_loadding_widget.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:get/get.dart'; typedef IndexedWidgetBuilder = Widget Function(BuildContext context, int index); class PageListView extends StatelessWidget { final BasePageController pageController; final IndexedWidgetBuilder itemBuilder; final IndexedWidgetBuilder? separatorBuilder; final EdgeInsets? padding; final bool firstRefresh; final Function()? onLoginSuccess; final bool showPageLoadding; final bool showPCRefreshButton; const PageListView({ required this.itemBuilder, required this.pageController, this.padding, this.firstRefresh = false, this.showPageLoadding = false, this.showPCRefreshButton = true, this.separatorBuilder, this.onLoginSuccess, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Obx( () => Stack( children: [ EasyRefresh( header: MaterialHeader( completeDuration: const Duration(milliseconds: 400), ), footer: MaterialFooter( completeDuration: const Duration(milliseconds: 400), ), scrollController: pageController.scrollController, controller: pageController.easyRefreshController, firstRefresh: firstRefresh, onLoad: pageController.loadData, onRefresh: pageController.refreshData, child: ListView.separated( padding: padding, itemCount: pageController.list.length, itemBuilder: itemBuilder, separatorBuilder: separatorBuilder ?? (context, i) => const SizedBox(), ), ), Positioned( bottom: 0, left: 0, right: 0, child: // 加载更多按钮 Visibility( visible: (Platform.isWindows || Platform.isLinux || Platform.isMacOS) && pageController.canLoadMore.value && !pageController.pageLoadding.value && !pageController.pageEmpty.value, child: Center( child: TextButton( onPressed: pageController.loadData, child: const Text("加载更多"), ), ), ), ), Positioned( bottom: 12, right: 12, child: // 加载更多按钮 Visibility( visible: (Platform.isWindows || Platform.isLinux || Platform.isMacOS) && pageController.canLoadMore.value && !pageController.pageLoadding.value && !pageController.pageEmpty.value && showPCRefreshButton, child: Center( child: IconButton( style: IconButton.styleFrom( backgroundColor: Get.theme.cardColor.withAlpha(200), elevation: 4, ), onPressed: () { pageController.refreshData(); }, icon: const Icon(Icons.refresh), ), ), ), ), Offstage( offstage: !pageController.pageEmpty.value, child: AppEmptyWidget( onRefresh: () => pageController.refreshData(), ), ), Offstage( offstage: !(showPageLoadding && pageController.pageLoadding.value), child: const AppLoaddingWidget(), ), Offstage( offstage: !pageController.pageError.value, child: AppErrorWidget( errorMsg: pageController.errorMsg.value, onRefresh: () => pageController.refreshData(), ), ), ], ), ); } } ================================================ FILE: simple_live_app/lib/widgets/rectangular_indicator.dart ================================================ import 'package:flutter/material.dart'; /// 来自 https://github.com/adar2378/tab_indicator_styler class RectangularIndicator extends Decoration { /// topRight radius of the indicator, default to 5. final double topRightRadius; /// topLeft radius of the indicator, default to 5. final double topLeftRadius; /// bottomRight radius of the indicator, default to 0. final double bottomRightRadius; /// bottomLeft radius of the indicator, default to 0 final double bottomLeftRadius; /// Color of the indicator, default set to [Colors.black] final Color color; /// Horizontal padding of the indicator, default set to 0 final double horizontalPadding; /// Vertical padding of the indicator, default set to 0 final double verticalPadding; /// [PagingStyle] determines if the indicator should be fill or stroke, default to fill final PaintingStyle paintingStyle; /// StrokeWidth, used for [PaintingStyle.stroke], default set to 0 final double strokeWidth; const RectangularIndicator({ this.topRightRadius = 5, this.topLeftRadius = 5, this.bottomRightRadius = 0, this.bottomLeftRadius = 0, this.color = Colors.black, this.horizontalPadding = 0, this.verticalPadding = 0, this.paintingStyle = PaintingStyle.fill, this.strokeWidth = 2, }); @override MyCustomPainter createBoxPainter([VoidCallback? onChanged]) { return MyCustomPainter( this, onChanged, bottomLeftRadius: bottomLeftRadius, bottomRightRadius: bottomRightRadius, color: color, horizontalPadding: horizontalPadding, topLeftRadius: topLeftRadius, topRightRadius: topRightRadius, verticalPadding: verticalPadding, paintingStyle: paintingStyle, strokeWidth: strokeWidth, ); } } class MyCustomPainter extends BoxPainter { final RectangularIndicator decoration; final double topRightRadius; final double topLeftRadius; final double bottomRightRadius; final double bottomLeftRadius; final Color color; final double horizontalPadding; final double verticalPadding; final PaintingStyle paintingStyle; final double strokeWidth; MyCustomPainter( this.decoration, VoidCallback? onChanged, { required this.topRightRadius, required this.topLeftRadius, required this.bottomRightRadius, required this.bottomLeftRadius, required this.color, required this.horizontalPadding, required this.verticalPadding, required this.paintingStyle, required this.strokeWidth, }) : super(onChanged); @override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(horizontalPadding >= 0); assert(horizontalPadding < configuration.size!.width / 2, "Padding must be less than half of the size of the tab"); assert(verticalPadding < configuration.size!.height / 2 && verticalPadding >= 0); assert(strokeWidth >= 0 && strokeWidth < configuration.size!.width / 2 && strokeWidth < configuration.size!.height / 2); //offset is the position from where the decoration should be drawn. //configuration.size tells us about the height and width of the tab. Size mysize = Size(configuration.size!.width - (horizontalPadding * 2), configuration.size!.height - (2 * verticalPadding)); Offset myoffset = Offset(offset.dx + (horizontalPadding), offset.dy + verticalPadding); final Rect rect = myoffset & mysize; final Paint paint = Paint(); paint.color = color; paint.style = paintingStyle; paint.strokeWidth = 3; canvas.drawRRect( RRect.fromRectAndCorners( rect, bottomRight: Radius.circular(bottomRightRadius), bottomLeft: Radius.circular(bottomLeftRadius), topLeft: Radius.circular(topLeftRadius), topRight: Radius.circular(topRightRadius), ), paint); } } ================================================ FILE: simple_live_app/lib/widgets/settings/settings_action.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; class SettingsAction extends StatelessWidget { final String title; final String? subtitle; final Function()? onTap; final String? value; final Widget? leading; const SettingsAction({ required this.title, this.value, this.onTap, this.subtitle, this.leading, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return ListTile( // visualDensity: VisualDensity.compact, leading: leading, title: Text( title, style: Theme.of(context).textTheme.bodyLarge, ), shape: RoundedRectangleBorder( borderRadius: AppStyle.radius8, ), contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8), subtitle: subtitle == null ? null : Text( subtitle!, style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ if (value != null) Text( value!, style: Theme.of(context) .textTheme .bodyMedium! .copyWith(color: Colors.grey), ), AppStyle.hGap4, const Icon( Icons.chevron_right, color: Colors.grey, ), ], ), onTap: onTap, ); } } ================================================ FILE: simple_live_app/lib/widgets/settings/settings_card.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; class SettingsCard extends StatelessWidget { final Widget child; const SettingsCard({required this.child, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Material( color: Theme.of(context).brightness == Brightness.dark ? Colors.grey.withAlpha(50) : Colors.white70, shape: RoundedRectangleBorder( borderRadius: AppStyle.radius8, side: BorderSide( color: Colors.grey.withAlpha(25), ), ), child: Container( decoration: BoxDecoration( borderRadius: AppStyle.radius8, ), child: child, ), ); } } ================================================ FILE: simple_live_app/lib/widgets/settings/settings_menu.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; class SettingsMenu extends StatelessWidget { final String title; final String? subtitle; final Map valueMap; final T value; final Function(T)? onChanged; const SettingsMenu({ required this.title, required this.value, required this.valueMap, this.subtitle, this.onChanged, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return ListTile( visualDensity: VisualDensity.compact, title: Text( title, style: Theme.of(context).textTheme.bodyLarge, ), shape: RoundedRectangleBorder( borderRadius: AppStyle.radius8, ), contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8), subtitle: subtitle == null ? null : Text( subtitle!, style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text( valueMap[value]!.tr, style: Theme.of(context) .textTheme .bodyMedium! .copyWith(color: Colors.grey), ), AppStyle.hGap4, const Icon( Icons.chevron_right, color: Colors.grey, ), ], ), onTap: () => openMenu(context), ); } void openMenu(BuildContext context) { showModalBottomSheet( context: context, showDragHandle: true, useSafeArea: true, //useSafeArea似乎无效 builder: (_) => SafeArea( top: false, child: SingleChildScrollView( child: RadioGroup( groupValue: value, onChanged: (e) { Get.back(); onChanged?.call(e as T); }, child: Column( mainAxisSize: MainAxisSize.min, children: valueMap.keys .map( (e) => RadioListTile( value: e, title: Text( (valueMap[e]?.tr) ?? "???", style: Get.textTheme.bodyMedium, ), ), ) .toList(), ), ), ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/settings/settings_number.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; class SettingsNumber extends StatelessWidget { final String title; final String? subtitle; final String unit; final int value; final int step; final int min; final int max; final String? displayValue; final Function(int)? onChanged; const SettingsNumber( {required this.title, required this.value, required this.max, this.subtitle, this.onChanged, this.step = 1, this.min = 0, this.unit = '', this.displayValue, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ListTile( visualDensity: VisualDensity.compact, title: Text( title, style: Get.textTheme.bodyLarge, ), shape: RoundedRectangleBorder( borderRadius: AppStyle.radius8, ), subtitle: subtitle == null ? null : Text( subtitle!, style: Get.textTheme.bodySmall!.copyWith(color: Colors.grey), ), contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 12), trailing: Container( decoration: BoxDecoration( color: Colors.grey.withAlpha(25), borderRadius: AppStyle.radius24, ), height: 36, child: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( padding: AppStyle.edgeInsetsA4, constraints: const BoxConstraints( minHeight: 32, ), onPressed: () { int newValue = value - step; if (newValue < min) { newValue = min; } onChanged?.call(newValue); }, icon: Icon( Icons.remove, color: Get.textTheme.bodyMedium!.color!.withAlpha(150), ), ), Text( displayValue ?? "$value$unit", textAlign: TextAlign.center, style: Theme.of(context) .textTheme .bodyMedium! .copyWith(color: Colors.grey), ), IconButton( padding: AppStyle.edgeInsetsA4, constraints: const BoxConstraints( minHeight: 32, ), onPressed: () { int newValue = value + step; if (newValue > max) { newValue = max; } onChanged?.call(newValue); }, icon: Icon( Icons.add, color: Get.textTheme.bodyMedium!.color!.withAlpha(150), ), ), ], ), ), onTap: () => openSilder(context), ); } void openSilder(BuildContext context) { var newValue = value.obs; showModalBottomSheet( context: context, showDragHandle: true, useSafeArea: true, //useSafeArea似乎无效 builder: (_) => SafeArea( top: false, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: AppStyle.edgeInsetsH16, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( title, style: Get.textTheme.titleMedium, ), Obx( () => Text( "${newValue.value}$unit", style: Get.textTheme.titleMedium, ), ), ], ), ), Obx( () => Slider( value: newValue.value.toDouble(), min: min.toDouble(), max: max.toDouble(), onChanged: (e) { newValue.value = e.toInt(); }, ), ), Padding( padding: AppStyle.edgeInsetsH16, child: TextButton( onPressed: () { onChanged?.call(newValue.value); Get.back(); }, child: const Text("确定"), ), ), ], ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/settings/settings_switch.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; class SettingsSwitch extends StatelessWidget { final bool value; final String title; final String? subtitle; final Function(bool) onChanged; const SettingsSwitch({ required this.value, required this.title, this.subtitle, required this.onChanged, super.key, }); @override Widget build(BuildContext context) { return SwitchListTile( title: Text( title, style: Theme.of(context).textTheme.bodyLarge, ), shape: RoundedRectangleBorder( borderRadius: AppStyle.radius8, ), trackOutlineColor: const WidgetStatePropertyAll(Colors.transparent), //visualDensity: VisualDensity.compact, contentPadding: AppStyle.edgeInsetsL16.copyWith(right: 8), subtitle: subtitle != null ? Text( subtitle!, style: Theme.of(context) .textTheme .bodySmall! .copyWith(color: Colors.grey), ) : null, value: value, onChanged: onChanged, ); } } ================================================ FILE: simple_live_app/lib/widgets/shadow_card.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; class ShadowCard extends StatelessWidget { final Widget child; final double radius; final Function()? onTap; const ShadowCard({ required this.child, this.radius = 8.0, this.onTap, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(radius), boxShadow: Get.isDarkMode ? [] : [ BoxShadow( blurRadius: 4, color: Colors.grey.withAlpha(50), ) ], ), child: Material( color: Theme.of(context).cardColor, borderRadius: BorderRadius.circular(radius), child: InkWell( borderRadius: BorderRadius.circular(radius), onTap: onTap, child: Container( decoration: BoxDecoration( borderRadius: AppStyle.radius8, ), child: child, ), ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/status/app_empty_widget.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:lottie/lottie.dart'; class AppEmptyWidget extends StatelessWidget { final Function()? onRefresh; const AppEmptyWidget({this.onRefresh, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: GestureDetector( onTap: () { onRefresh?.call(); }, child: Padding( padding: AppStyle.edgeInsetsA12, child: Column( mainAxisSize: MainAxisSize.min, children: [ LottieBuilder.asset( 'assets/lotties/empty.json', width: 200, height: 200, repeat: false, ), const Text( "这里什么都没有", textAlign: TextAlign.center, style: TextStyle(fontSize: 12, color: Colors.grey), ), ], ), ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/status/app_error_widget.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:lottie/lottie.dart'; class AppErrorWidget extends StatelessWidget { final Function()? onRefresh; final String errorMsg; const AppErrorWidget({this.errorMsg = "", this.onRefresh, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: GestureDetector( onTap: () { onRefresh?.call(); }, child: Padding( padding: AppStyle.edgeInsetsA12, child: Column( mainAxisSize: MainAxisSize.min, children: [ LottieBuilder.asset( 'assets/lotties/error.json', width: 260, repeat: false, ), Text( "$errorMsg\r\n点击刷新", textAlign: TextAlign.center, style: const TextStyle(fontSize: 12, color: Colors.grey), ), ], ), ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/status/app_loadding_widget.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_app/app/app_style.dart'; class AppLoaddingWidget extends StatelessWidget { const AppLoaddingWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: Container( padding: AppStyle.edgeInsetsA12, decoration: BoxDecoration( shape: BoxShape.circle, color: Theme.of(context).cardColor, boxShadow: Get.isDarkMode ? [] : [ BoxShadow( blurRadius: 4, color: Colors.grey.withAlpha(50), ) ], ), child: const CupertinoActivityIndicator( radius: 10, ), ), ); } } ================================================ FILE: simple_live_app/lib/widgets/superchat_card.dart ================================================ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:simple_live_app/app/app_style.dart'; import 'package:simple_live_app/app/utils.dart'; import 'package:simple_live_app/widgets/net_image.dart'; import 'package:simple_live_core/simple_live_core.dart'; class SuperChatCard extends StatefulWidget { final LiveSuperChatMessage message; final Function()? onExpire; final int? customCountdown; const SuperChatCard( this.message, { required this.onExpire, this.customCountdown, Key? key, }) : super(key: key); @override State createState() => _SuperChatCardState(); } class _SuperChatCardState extends State { late Timer timer; int countdown = 0; @override void initState() { var currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; var endTime = widget.message.endTime.millisecondsSinceEpoch ~/ 1000; countdown = endTime - currentTime; timer = Timer.periodic(const Duration(seconds: 1), timerCallback); super.initState(); } void timerCallback(e) { if (countdown <= 0) { widget.onExpire?.call(); timer.cancel(); return; } setState(() { countdown -= 1; }); } @override Widget build(BuildContext context) { final displayCountdown = widget.customCountdown ?? countdown; return ClipRRect( borderRadius: AppStyle.radius8, child: Container( decoration: BoxDecoration( color: Utils.convertHexColor(widget.message.backgroundColor), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: AppStyle.edgeInsetsA8, child: Row( children: [ NetImage( widget.message.face, width: 48, height: 48, borderRadius: 36, ), AppStyle.hGap12, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( widget.message.userName, style: const TextStyle( color: AppColors.black333, ), ), Text( "¥${widget.message.price}", style: const TextStyle( fontSize: 12, color: Colors.grey, ), ), ], ), ), Text( "$displayCountdown", style: const TextStyle( fontSize: 14, color: Colors.grey, ), ), ], ), ), Container( decoration: BoxDecoration( color: Utils.convertHexColor(widget.message.backgroundBottomColor), ), padding: AppStyle.edgeInsetsA8, child: Text( widget.message.message, style: const TextStyle(color: Colors.white), ), ), ], ), ), ); } @override void dispose() { timer.cancel(); super.dispose(); } } ================================================ FILE: simple_live_app/linux/.gitignore ================================================ flutter/ephemeral ================================================ FILE: simple_live_app/linux/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.13) project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "simple_live_app") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID set(APPLICATION_ID "com.xycz.simple_live_app") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(SET CMP0063 NEW) # Load bundled libraries from the lib/ directory relative to the binary. set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") # Root filesystem for cross-building. if(FLUTTER_TARGET_PLATFORM_SYSROOT) set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) endif() # Define build configuration options. if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_14) target_compile_options(${TARGET} PRIVATE -Wall -Werror) target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) # Only the install-generated bundle's copy of the executable will launch # correctly, since the resources must in the right relative locations. To avoid # people trying to run the unbundled copy, put it in a subdirectory instead of # the default top-level location. set_target_properties(${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" ) # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # By default, "installing" just makes a relocatable bundle in the build # directory. set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() # Start with a clean build bundle directory every time. install(CODE " file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") " COMPONENT Runtime) set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) install(FILES "${bundled_library}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endforeach(bundled_library) # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") install(DIRECTORY "${NATIVE_ASSETS_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() ================================================ FILE: simple_live_app/linux/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.10) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. # Serves the same purpose as list(TRANSFORM ... PREPEND ...), # which isn't available in 3.10. function(list_prepend LIST_NAME PREFIX) set(NEW_LIST "") foreach(element ${${LIST_NAME}}) list(APPEND NEW_LIST "${PREFIX}${element}") endforeach(element) set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) endfunction() # === Flutter Library === # System-level dependencies. find_package(PkgConfig REQUIRED) pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "fl_basic_message_channel.h" "fl_binary_codec.h" "fl_binary_messenger.h" "fl_dart_project.h" "fl_engine.h" "fl_json_message_codec.h" "fl_json_method_codec.h" "fl_message_codec.h" "fl_method_call.h" "fl_method_channel.h" "fl_method_codec.h" "fl_method_response.h" "fl_plugin_registrar.h" "fl_plugin_registry.h" "fl_standard_message_codec.h" "fl_standard_method_codec.h" "fl_string_codec.h" "fl_value.h" "fl_view.h" "flutter_linux.h" ) list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") target_link_libraries(flutter INTERFACE PkgConfig::GTK PkgConfig::GLIB PkgConfig::GIO ) add_dependencies(flutter flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/_phony_ COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ) ================================================ FILE: simple_live_app/linux/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include #include #include #include #include #include #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) dynamic_color_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "DynamicColorPlugin"); dynamic_color_plugin_register_with_registrar(dynamic_color_registrar); g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); g_autoptr(FlPluginRegistrar) media_kit_video_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitVideoPlugin"); media_kit_video_plugin_register_with_registrar(media_kit_video_registrar); g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); g_autoptr(FlPluginRegistrar) volume_controller_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "VolumeControllerPlugin"); volume_controller_plugin_register_with_registrar(volume_controller_registrar); g_autoptr(FlPluginRegistrar) window_manager_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); window_manager_plugin_register_with_registrar(window_manager_registrar); } ================================================ FILE: simple_live_app/linux/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void fl_register_plugins(FlPluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: simple_live_app/linux/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST dynamic_color media_kit_libs_linux media_kit_video screen_retriever_linux url_launcher_linux volume_controller window_manager ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: simple_live_app/linux/packaging/deb/make_config.yaml ================================================ display_name: Simple-Live package_name: simple-live maintainer: name: xiaoyaocz email: xiaoyaocz@52uwp.com priority: optional section: x11 installed_size: 24400 essential: false icon: assets/logo.png keywords: - Simple Live generic_name: Simple-Live categories: - Media startup_notify: true ================================================ FILE: simple_live_app/linux/runner/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.13) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} "main.cc" "my_application.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the application ID. add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") ================================================ FILE: simple_live_app/linux/runner/main.cc ================================================ #include "my_application.h" int main(int argc, char** argv) { g_autoptr(MyApplication) app = my_application_new(); return g_application_run(G_APPLICATION(app), argc, argv); } ================================================ FILE: simple_live_app/linux/runner/my_application.cc ================================================ #include "my_application.h" #include #ifdef GDK_WINDOWING_X11 #include #endif #include "flutter/generated_plugin_registrant.h" struct _MyApplication { GtkApplication parent_instance; char** dart_entrypoint_arguments; }; G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) // Called when first Flutter frame received. static void first_frame_cb(MyApplication* self, FlView* view) { gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view))); } // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); // Use a header bar when running in GNOME as this is the common style used // by applications and is the setup most users will be using (e.g. Ubuntu // desktop). // If running on X and not using GNOME then just use a traditional title bar // in case the window manager does more exotic layout, e.g. tiling. // If running on Wayland assume the header bar will work (may need changing // if future cases occur). gboolean use_header_bar = TRUE; #ifdef GDK_WINDOWING_X11 GdkScreen* screen = gtk_window_get_screen(window); if (GDK_IS_X11_SCREEN(screen)) { const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); if (g_strcmp0(wm_name, "GNOME Shell") != 0) { use_header_bar = FALSE; } } #endif if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); gtk_header_bar_set_title(header_bar, "simple_live_app"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { gtk_window_set_title(window, "simple_live_app"); } gtk_window_set_default_size(window, 1280, 720); g_autoptr(FlDartProject) project = fl_dart_project_new(); fl_dart_project_set_dart_entrypoint_arguments( project, self->dart_entrypoint_arguments); FlView* view = fl_view_new(project); GdkRGBA background_color; // Background defaults to black, override it here if necessary, e.g. #00000000 // for transparent. gdk_rgba_parse(&background_color, "#000000"); fl_view_set_background_color(view, &background_color); gtk_widget_show(GTK_WIDGET(view)); gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); // Show the window when Flutter renders. // Requires the view to be realized so we can start rendering. g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb), self); gtk_widget_realize(GTK_WIDGET(view)); fl_register_plugins(FL_PLUGIN_REGISTRY(view)); gtk_widget_grab_focus(GTK_WIDGET(view)); } // Implements GApplication::local_command_line. static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { MyApplication* self = MY_APPLICATION(application); // Strip out the first argument as it is the binary name. self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); g_autoptr(GError) error = nullptr; if (!g_application_register(application, nullptr, &error)) { g_warning("Failed to register: %s", error->message); *exit_status = 1; return TRUE; } g_application_activate(application); *exit_status = 0; return TRUE; } // Implements GApplication::startup. static void my_application_startup(GApplication* application) { // MyApplication* self = MY_APPLICATION(object); // Perform any actions required at application startup. G_APPLICATION_CLASS(my_application_parent_class)->startup(application); } // Implements GApplication::shutdown. static void my_application_shutdown(GApplication* application) { // MyApplication* self = MY_APPLICATION(object); // Perform any actions required at application shutdown. G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); } // Implements GObject::dispose. static void my_application_dispose(GObject* object) { MyApplication* self = MY_APPLICATION(object); g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); G_OBJECT_CLASS(my_application_parent_class)->dispose(object); } static void my_application_class_init(MyApplicationClass* klass) { G_APPLICATION_CLASS(klass)->activate = my_application_activate; G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; G_APPLICATION_CLASS(klass)->startup = my_application_startup; G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; G_OBJECT_CLASS(klass)->dispose = my_application_dispose; } static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { // Set the program name to the application ID, which helps various systems // like GTK and desktop environments map this running application to its // corresponding .desktop file. This ensures better integration by allowing // the application to be recognized beyond its binary name. g_set_prgname(APPLICATION_ID); return MY_APPLICATION(g_object_new(my_application_get_type(), "application-id", APPLICATION_ID, "flags", G_APPLICATION_NON_UNIQUE, nullptr)); } ================================================ FILE: simple_live_app/linux/runner/my_application.h ================================================ #ifndef FLUTTER_MY_APPLICATION_H_ #define FLUTTER_MY_APPLICATION_H_ #include G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, GtkApplication) /** * my_application_new: * * Creates a new Flutter-based application. * * Returns: a new #MyApplication. */ MyApplication* my_application_new(); #endif // FLUTTER_MY_APPLICATION_H_ ================================================ FILE: simple_live_app/macos/.gitignore ================================================ # Flutter-related **/Flutter/ephemeral/ **/Pods/ # Xcode-related **/dgph **/xcuserdata/ ================================================ FILE: simple_live_app/macos/Flutter/Flutter-Debug.xcconfig ================================================ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" ================================================ FILE: simple_live_app/macos/Flutter/Flutter-Release.xcconfig ================================================ #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "ephemeral/Flutter-Generated.xcconfig" ================================================ FILE: simple_live_app/macos/Flutter/GeneratedPluginRegistrant.swift ================================================ // // Generated file. Do not edit. // import FlutterMacOS import Foundation import connectivity_plus import device_info_plus import dynamic_color import file_picker import flutter_inappwebview_macos import media_kit_libs_macos_video import media_kit_video import network_info_plus import package_info_plus import path_provider_foundation import screen_brightness_macos import screen_retriever_macos import share_plus import url_launcher_macos import volume_controller import wakelock_plus import window_manager func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DynamicColorPlugin.register(with: registry.registrar(forPlugin: "DynamicColorPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenBrightnessMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenBrightnessMacosPlugin")) ScreenRetrieverMacosPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverMacosPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VolumeControllerPlugin.register(with: registry.registrar(forPlugin: "VolumeControllerPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) } ================================================ FILE: simple_live_app/macos/Podfile ================================================ platform :osx, '10.14' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' project 'Runner', { 'Debug' => :debug, 'Profile' => :release, 'Release' => :release, } def flutter_root generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) unless File.exist?(generated_xcode_build_settings_path) raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" end File.foreach(generated_xcode_build_settings_path) do |line| matches = line.match(/FLUTTER_ROOT\=(.*)/) return matches[1].strip if matches end raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" end require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) flutter_macos_podfile_setup target 'Runner' do use_frameworks! use_modular_headers! flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) target 'RunnerTests' do inherit! :search_paths end end post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_macos_build_settings(target) end end ================================================ FILE: simple_live_app/macos/Runner/AppDelegate.swift ================================================ import Cocoa import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true } } ================================================ FILE: simple_live_app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images": [ { "size": "16x16", "idiom": "mac", "filename": "icon-16.png", "scale": "1x" }, { "size": "16x16", "idiom": "mac", "filename": "icon-16@2x.png", "scale": "2x" }, { "size": "32x32", "idiom": "mac", "filename": "icon-32.png", "scale": "1x" }, { "size": "32x32", "idiom": "mac", "filename": "icon-32@2x.png", "scale": "2x" }, { "size": "128x128", "idiom": "mac", "filename": "icon-128.png", "scale": "1x" }, { "size": "128x128", "idiom": "mac", "filename": "icon-128@2x.png", "scale": "2x" }, { "size": "256x256", "idiom": "mac", "filename": "icon-256.png", "scale": "1x" }, { "size": "256x256", "idiom": "mac", "filename": "icon-256@2x.png", "scale": "2x" }, { "size": "512x512", "idiom": "mac", "filename": "icon-512.png", "scale": "1x" }, { "size": "512x512", "idiom": "mac", "filename": "icon-512@2x.png", "scale": "2x" } ], "info": { "version": 1, "author": "icon.wuruihong.com" } } ================================================ FILE: simple_live_app/macos/Runner/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: simple_live_app/macos/Runner/Base.lproj/MainMenu.xib ================================================ ================================================ FILE: simple_live_app/macos/Runner/Configs/AppInfo.xcconfig ================================================ // Application-level settings for the Runner target. // // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the // future. If not, the values below would default to using the project name when this becomes a // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. PRODUCT_NAME = Simple Live // The application's bundle identifier PRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2023 com.xycz. All rights reserved. ================================================ FILE: simple_live_app/macos/Runner/Configs/Debug.xcconfig ================================================ #include "../../Flutter/Flutter-Debug.xcconfig" #include "Warnings.xcconfig" ================================================ FILE: simple_live_app/macos/Runner/Configs/Release.xcconfig ================================================ #include "../../Flutter/Flutter-Release.xcconfig" #include "Warnings.xcconfig" ================================================ FILE: simple_live_app/macos/Runner/Configs/Warnings.xcconfig ================================================ WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings GCC_WARN_UNDECLARED_SELECTOR = YES CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE CLANG_WARN__DUPLICATE_METHOD_MATCH = YES CLANG_WARN_PRAGMA_PACK = YES CLANG_WARN_STRICT_PROTOTYPES = YES CLANG_WARN_COMMA = YES GCC_WARN_STRICT_SELECTOR_MATCH = YES CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES GCC_WARN_SHADOW = YES CLANG_WARN_UNREACHABLE_CODE = YES ================================================ FILE: simple_live_app/macos/Runner/DebugProfile.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.cs.allow-jit com.apple.security.network.server com.apple.security.network.client com.apple.security.files.user-selected.read-write ================================================ FILE: simple_live_app/macos/Runner/Info.plist ================================================ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(FLUTTER_BUILD_NAME) CFBundleVersion $(FLUTTER_BUILD_NUMBER) LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSHumanReadableCopyright $(PRODUCT_COPYRIGHT) NSMainNibFile MainMenu NSPrincipalClass NSApplication ================================================ FILE: simple_live_app/macos/Runner/MainFlutterWindow.swift ================================================ import Cocoa import FlutterMacOS class MainFlutterWindow: NSWindow { override func awakeFromNib() { let flutterViewController = FlutterViewController() let windowFrame = self.frame self.contentViewController = flutterViewController self.setFrame(windowFrame, display: true) RegisterGeneratedPlugins(registry: flutterViewController) super.awakeFromNib() } } ================================================ FILE: simple_live_app/macos/Runner/Release.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.network.client com.apple.security.files.user-selected.read-write com.apple.security.network.server ================================================ FILE: simple_live_app/macos/Runner.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { isa = PBXAggregateTarget; buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; buildPhases = ( 33CC111E2044C6BF0003C045 /* ShellScript */, ); dependencies = ( ); name = "Flutter Assemble"; productName = FLX; }; /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 33E8CA35C15B26E48DA4EBD7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4C1377411379D99120C8F83 /* Pods_Runner.framework */; }; 9E6C57AAF7AD9FA590476061 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AEF14C9BF8504F57660D2A38 /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC10EC2044A3C60003C045; remoteInfo = Runner; }; 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 33CC10E52044A3C60003C045 /* Project object */; proxyType = 1; remoteGlobalIDString = 33CC111A2044C6BA0003C045; remoteInfo = FLX; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 33CC110E2044A8840003C045 /* Bundle Framework */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( ); name = "Bundle Framework"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 22F821424EC724046ABB4672 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 33CC10ED2044A3C60003C045 /* simple_live_app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = simple_live_app.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 63D7158B8577651B73F3032F /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 7E3E460DBF561AAF73690196 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; AEF14C9BF8504F57660D2A38 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B51A5741C0A7E288C9368C1A /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; C7907028FBA71F2E559043FF /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; D4C1377411379D99120C8F83 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D9BBDE6BF6193671AE9960B0 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 331C80D2294CF70F00263BE5 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 9E6C57AAF7AD9FA590476061 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EA2044A3C60003C045 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 33E8CA35C15B26E48DA4EBD7 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 24357D9109B54496E939BAD5 /* Pods */ = { isa = PBXGroup; children = ( 22F821424EC724046ABB4672 /* Pods-Runner.debug.xcconfig */, C7907028FBA71F2E559043FF /* Pods-Runner.release.xcconfig */, B51A5741C0A7E288C9368C1A /* Pods-Runner.profile.xcconfig */, 63D7158B8577651B73F3032F /* Pods-RunnerTests.debug.xcconfig */, D9BBDE6BF6193671AE9960B0 /* Pods-RunnerTests.release.xcconfig */, 7E3E460DBF561AAF73690196 /* Pods-RunnerTests.profile.xcconfig */, ); name = Pods; path = Pods; sourceTree = ""; }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( 331C80D7294CF71000263BE5 /* RunnerTests.swift */, ); path = RunnerTests; sourceTree = ""; }; 33BA886A226E78AF003329D5 /* Configs */ = { isa = PBXGroup; children = ( 33E5194F232828860026EE4D /* AppInfo.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, ); path = Configs; sourceTree = ""; }; 33CC10E42044A3C60003C045 = { isa = PBXGroup; children = ( 33FAB671232836740065AC1E /* Runner */, 33CEB47122A05771004F2AC0 /* Flutter */, 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, 24357D9109B54496E939BAD5 /* Pods */, ); sourceTree = ""; }; 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( 33CC10ED2044A3C60003C045 /* simple_live_app.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; sourceTree = ""; }; 33CC11242044D66E0003C045 /* Resources */ = { isa = PBXGroup; children = ( 33CC10F22044A3C60003C045 /* Assets.xcassets */, 33CC10F42044A3C60003C045 /* MainMenu.xib */, 33CC10F72044A3C60003C045 /* Info.plist */, ); name = Resources; path = ..; sourceTree = ""; }; 33CEB47122A05771004F2AC0 /* Flutter */ = { isa = PBXGroup; children = ( 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, ); path = Flutter; sourceTree = ""; }; 33FAB671232836740065AC1E /* Runner */ = { isa = PBXGroup; children = ( 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 33E51914231749380026EE4D /* Release.entitlements */, 33CC11242044D66E0003C045 /* Resources */, 33BA886A226E78AF003329D5 /* Configs */, ); path = Runner; sourceTree = ""; }; D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( D4C1377411379D99120C8F83 /* Pods_Runner.framework */, AEF14C9BF8504F57660D2A38 /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 331C80D4294CF70F00263BE5 /* RunnerTests */ = { isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( 1C0ABA43D8228815BB859BFE /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, ); buildRules = ( ); dependencies = ( 331C80DA294CF71000263BE5 /* PBXTargetDependency */, ); name = RunnerTests; productName = RunnerTests; productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 33CC10EC2044A3C60003C045 /* Runner */ = { isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( 671FAACF9F58D03A0C709E83 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, A261E453836422CA4D990339 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( 33CC11202044C79F0003C045 /* PBXTargetDependency */, ); name = Runner; productName = Runner; productReference = 33CC10ED2044A3C60003C045 /* simple_live_app.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 33CC10E52044A3C60003C045 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { CreatedOnToolsVersion = 14.0; TestTargetID = 33CC10EC2044A3C60003C045; }; 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Sandbox = { enabled = 1; }; }; }; 33CC111A2044C6BA0003C045 = { CreatedOnToolsVersion = 9.2; ProvisioningStyle = Manual; }; }; }; buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; compatibilityVersion = "Xcode 9.3"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 33CC10E42044A3C60003C045; productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 33CC10EC2044A3C60003C045 /* Runner */, 331C80D4294CF70F00263BE5 /* RunnerTests */, 33CC111A2044C6BA0003C045 /* Flutter Assemble */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 331C80D3294CF70F00263BE5 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10EB2044A3C60003C045 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 1C0ABA43D8228815BB859BFE /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( ); outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; }; 33CC111E2044C6BF0003C045 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( Flutter/ephemeral/FlutterInputs.xcfilelist, ); inputPaths = ( Flutter/ephemeral/tripwire, ); outputFileListPaths = ( Flutter/ephemeral/FlutterOutputs.xcfilelist, ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; 671FAACF9F58D03A0C709E83 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( ); inputPaths = ( "${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Manifest.lock", ); name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( ); outputPaths = ( "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; A261E453836422CA4D990339 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 331C80D1294CF70F00263BE5 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 33CC10E92044A3C60003C045 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC10EC2044A3C60003C045 /* Runner */; targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; }; 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 33CC10F52044A3C60003C045 /* Base */, ); name = MainMenu.xib; path = Runner; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 63D7158B8577651B73F3032F /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/simple_live_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_live_app"; }; name = Debug; }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = D9BBDE6BF6193671AE9960B0 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/simple_live_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_live_app"; }; name = Release; }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7E3E460DBF561AAF73690196 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.xycz.simpleLiveApp.RunnerTests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/simple_live_app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/simple_live_app"; }; name = Profile; }; 338D0CE9231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Profile; }; 338D0CEA231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Profile; }; 338D0CEB231458BD00FA5F75 /* Profile */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Profile; }; 33CC10F92044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 33CC10FA2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 33CC10FC2044A3C60003C045 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; }; name = Debug; }; 33CC10FD2044A3C60003C045 /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Release; }; 33CC111C2044C6BA0003C045 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Manual; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; }; 33CC111D2044C6BA0003C045 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 331C80DB294CF71000263BE5 /* Debug */, 331C80DC294CF71000263BE5 /* Release */, 331C80DD294CF71000263BE5 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10F92044A3C60003C045 /* Debug */, 33CC10FA2044A3C60003C045 /* Release */, 338D0CE9231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC10FC2044A3C60003C045 /* Debug */, 33CC10FD2044A3C60003C045 /* Release */, 338D0CEA231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { isa = XCConfigurationList; buildConfigurations = ( 33CC111C2044C6BA0003C045 /* Debug */, 33CC111D2044C6BA0003C045 /* Release */, 338D0CEB231458BD00FA5F75 /* Profile */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 33CC10E52044A3C60003C045 /* Project object */; } ================================================ FILE: simple_live_app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: simple_live_app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme ================================================ ================================================ FILE: simple_live_app/macos/Runner.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: simple_live_app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: simple_live_app/macos/RunnerTests/RunnerTests.swift ================================================ import FlutterMacOS import Cocoa import XCTest class RunnerTests: XCTestCase { func testExample() { // If you add code to the Runner application, consider adding tests here. // See https://developer.apple.com/documentation/xctest for more information about using XCTest. } } ================================================ FILE: simple_live_app/macos/packaging/dmg/make_config.yaml ================================================ title: Simple Live contents: - x: 448 y: 344 type: link path: "/Applications" - x: 192 y: 344 type: file path: Simple Live.app ================================================ FILE: simple_live_app/pubspec.yaml ================================================ name: simple_live_app version: 1.11.4+11104 publish_to: none description: "Simple Live APP" environment: sdk: ">=3.0.5 <4.0.0" dependencies: simple_live_core: path: ../simple_live_core # 图标 cupertino_icons: ^1.0.8 remixicon: ^1.4.1 #Remix图标 # 框架、工具 get: ^4.7.3 #状态管理、路由管理、国际化 dio: ^5.9.0 #网络请求 hive: 2.2.3 #持久化存储 hive_flutter: 1.1.0 #持久化存储 logger: ^2.6.2 #日志 intl: ^0.20.2 #国际化 qr_flutter: ^4.1.0 #二维码生成 dynamic_color: ^1.8.1 #动态颜色 path: any collection: any udp: ^5.0.3 #UDP uuid: ^4.5.2 #UUID webdav_client: ^1.2.2 # WebDAV archive: ^4.0.7 #文件压缩 crypto: ^3.0.7 #Widget flutter_staggered_grid_view: ^0.7.0 #瀑布流/GridView flutter_easyrefresh: 2.2.2 #下拉刷新、上拉加载 extended_image: ^10.0.1 #拓展Image,支持缓存 flutter_smart_dialog: ^4.9.8+9 #各种弹窗 Toast/Dialog/Popup sticky_headers: ^0.3.0+2 #吸顶 lottie: ^3.3.2 #lottie动画 canvas_danmaku: ^0.2.7 # ns_danmaku: #弹幕 # git: # url: https://github.com/xiaoyaocz/flutter_ns_danmaku.git # tag: v0.0.9 #系统交互 package_info_plus: ^9.0.0 #包信息 device_info_plus: ^12.2.0 #设备信息 url_launcher: ^6.3.2 #打开链接 share_plus: ^12.0.1 #分享 path_provider: ^2.1.5 #常用路径 cross_file: ^0.3.5 #跨平台文件 permission_handler: ^12.0.1 #权限处理 image_gallery_saver_plus: ^4.0.1 #图片保存到相册 screen_brightness: ^2.1.7 #亮度控制 auto_orientation_v2: ^2.3.6 #屏幕方向 wakelock_plus: ^1.4.0 #屏幕常亮 file_picker: ^10.3.7 #文件选择 window_manager: ^0.5.1 #窗口管理 floating: ^6.0.0 #PIP画中画 flutter_inappwebview: ^6.1.5 #WebView connectivity_plus: ^7.0.0 #网络状态 qr_code_scanner_plus: ^2.0.14 #二维码扫描 volume_controller: ^3.4.0 #音量控制 # 网络相关 shelf: ^1.4.2 shelf_router: ^1.1.4 network_info_plus: ^7.0.0 signalr_netcore: ^1.4.4 #SignalR # 视频播放 media_kit: ^1.2.2 media_kit_video: ^2.0.0 media_kit_libs_video: ^1.0.7 flutter: sdk: flutter flutter_localizations: sdk: flutter dev_dependencies: flutter_lints: ^2.0.0 build_runner: ^2.3.3 hive_generator: ^2.0.0 flutter_launcher_icons: ^0.13.1 flutter_test: sdk: flutter flutter_launcher_icons: android: true ios: true image_path: "assets/logo.png" min_sdk_android: 21 macos: generate: true flutter: uses-material-design: true assets: - assets/statement.txt - assets/images/ - assets/icons/ - assets/lotties/ ================================================ FILE: simple_live_app/test/widget_test.dart ================================================ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester // utility in the flutter_test package. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:simple_live_app/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(const MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); } ================================================ FILE: simple_live_app/windows/.gitignore ================================================ flutter/ephemeral/ # Visual Studio user-specific files. *.suo *.user *.userosscache *.sln.docstates # Visual Studio build-related files. x64/ x86/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ ================================================ FILE: simple_live_app/windows/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.14) project(simple_live_app LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "simple_live_app") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(VERSION 3.14...3.25) # Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" CACHE STRING "" FORCE) else() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() endif() # Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # Support files are copied into place next to the executable, so that it can # run in place. This is done instead of making a separate bundle (as on Linux) # so that building and running from within Visual Studio will work. set(BUILD_BUNDLE_DIR "$") # Make the "install" step default, as it's required to run. set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() # Copy the native assets provided by the build.dart from all packages. set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") install(DIRECTORY "${NATIVE_ASSETS_DIR}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) ================================================ FILE: simple_live_app/windows/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") # Set fallback configurations for older versions of the flutter tool. if (NOT DEFINED FLUTTER_TARGET_PLATFORM) set(FLUTTER_TARGET_PLATFORM "windows-x64") endif() # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_export.h" "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") add_dependencies(flutter flutter_assemble) # === Wrapper === list(APPEND CPP_WRAPPER_SOURCES_CORE "core_implementations.cc" "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_PLUGIN "plugin_registrar.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" "flutter_view_controller.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) set_target_properties(flutter_wrapper_plugin PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(flutter_wrapper_plugin PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_include_directories(flutter_wrapper_plugin PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_plugin flutter_assemble) # Wrapper sources needed for the runner. add_library(flutter_wrapper_app STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_APP} ) apply_standard_settings(flutter_wrapper_app) target_link_libraries(flutter_wrapper_app PUBLIC flutter) target_include_directories(flutter_wrapper_app PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_app flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) ================================================ FILE: simple_live_app/windows/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include #include #include #include #include #include #include #include #include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); DynamicColorPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("DynamicColorPluginCApi")); FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); MediaKitVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); ScreenBrightnessWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin")); ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); SharePlusWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); VolumeControllerPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("VolumeControllerPluginCApi")); WindowManagerPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowManagerPlugin")); } ================================================ FILE: simple_live_app/windows/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void RegisterPlugins(flutter::PluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: simple_live_app/windows/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus dynamic_color flutter_inappwebview_windows media_kit_libs_windows_video media_kit_video permission_handler_windows screen_brightness_windows screen_retriever_windows share_plus url_launcher_windows volume_controller window_manager ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: simple_live_app/windows/packaging/msix/make_config.yaml ================================================ display_name: Simple Live publisher_display_name: xiaoyaocz identity_name: com.xycz.simplelive logo_path: assets/logo_400.png capabilities: internetClient languages: zh-cn install_certificate: "false" ================================================ FILE: simple_live_app/windows/runner/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the build version. target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) ================================================ FILE: simple_live_app/windows/runner/Runner.rc ================================================ // Microsoft Visual C++ generated resource script. // #pragma code_page(65001) #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_APP_ICON ICON "resources\\app_icon.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else #define VERSION_AS_NUMBER 1,0,0,0 #endif #if defined(FLUTTER_VERSION) #define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_AS_NUMBER PRODUCTVERSION VERSION_AS_NUMBER FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "com.xycz" "\0" VALUE "FileDescription", "simple_live_app" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "simple_live_app" "\0" VALUE "LegalCopyright", "Copyright (C) 2025 com.xycz. All rights reserved." "\0" VALUE "OriginalFilename", "simple_live_app.exe" "\0" VALUE "ProductName", "simple_live_app" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: simple_live_app/windows/runner/flutter_window.cpp ================================================ #include "flutter_window.h" #include #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); // Flutter can complete the first frame before the "show window" callback is // registered. The following call ensures a frame is pending to ensure the // window is shown. It is a no-op if the first frame hasn't completed yet. flutter_controller_->ForceRedraw(); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); } ================================================ FILE: simple_live_app/windows/runner/flutter_window.h ================================================ #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ #include #include #include #include "win32_window.h" // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: // Creates a new FlutterWindow hosting a Flutter view running |project|. explicit FlutterWindow(const flutter::DartProject& project); virtual ~FlutterWindow(); protected: // Win32Window: bool OnCreate() override; void OnDestroy() override; LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override; private: // The project to run. flutter::DartProject project_; // The Flutter instance hosted by this window. std::unique_ptr flutter_controller_; }; #endif // RUNNER_FLUTTER_WINDOW_H_ ================================================ FILE: simple_live_app/windows/runner/main.cpp ================================================ #include #include #include #include "flutter_window.h" #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { CreateAndAttachConsole(); } // Initialize COM, so that it is available for use in the library and/or // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); flutter::DartProject project(L"data"); std::vector command_line_arguments = GetCommandLineArguments(); project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.Create(L"simple_live_app", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ::MSG msg; while (::GetMessage(&msg, nullptr, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::CoUninitialize(); return EXIT_SUCCESS; } ================================================ FILE: simple_live_app/windows/runner/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Runner.rc // #define IDI_APP_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: simple_live_app/windows/runner/runner.exe.manifest ================================================ PerMonitorV2 ================================================ FILE: simple_live_app/windows/runner/utils.cpp ================================================ #include "utils.h" #include #include #include #include #include void CreateAndAttachConsole() { if (::AllocConsole()) { FILE *unused; if (freopen_s(&unused, "CONOUT$", "w", stdout)) { _dup2(_fileno(stdout), 1); } if (freopen_s(&unused, "CONOUT$", "w", stderr)) { _dup2(_fileno(stdout), 2); } std::ios::sync_with_stdio(); FlutterDesktopResyncOutputStreams(); } } std::vector GetCommandLineArguments() { // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. int argc; wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); if (argv == nullptr) { return std::vector(); } std::vector command_line_arguments; // Skip the first argument as it's the binary name. for (int i = 1; i < argc; i++) { command_line_arguments.push_back(Utf8FromUtf16(argv[i])); } ::LocalFree(argv); return command_line_arguments; } std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } unsigned int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr) -1; // remove the trailing null character int input_length = (int)wcslen(utf16_string); std::string utf8_string; if (target_length == 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); int converted_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, input_length, utf8_string.data(), target_length, nullptr, nullptr); if (converted_length == 0) { return std::string(); } return utf8_string; } ================================================ FILE: simple_live_app/windows/runner/utils.h ================================================ #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ #include #include // Creates a console for the process, and redirects stdout and stderr to // it for both the runner and the Flutter library. void CreateAndAttachConsole(); // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string // encoded in UTF-8. Returns an empty std::string on failure. std::string Utf8FromUtf16(const wchar_t* utf16_string); // Gets the command line arguments passed in as a std::vector, // encoded in UTF-8. Returns an empty std::vector on failure. std::vector GetCommandLineArguments(); #endif // RUNNER_UTILS_H_ ================================================ FILE: simple_live_app/windows/runner/win32_window.cpp ================================================ #include "win32_window.h" #include #include #include "resource.h" namespace { /// Window attribute that enables dark mode window decorations. /// /// Redefined in case the developer's machine has a Windows SDK older than /// version 10.0.22000.0. /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; /// Registry key for app theme preference. /// /// A value of 0 indicates apps should use dark mode. A non-zero or missing /// value indicates apps should use light mode. constexpr const wchar_t kGetPreferredBrightnessRegKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. // This API is only needed for PerMonitor V1 awareness mode. void EnableFullDpiSupportIfAvailable(HWND hwnd) { HMODULE user32_module = LoadLibraryA("User32.dll"); if (!user32_module) { return; } auto enable_non_client_dpi_scaling = reinterpret_cast( GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); } FreeLibrary(user32_module); } } // namespace // Manages the Win32Window's window class registration. class WindowClassRegistrar { public: ~WindowClassRegistrar() = default; // Returns the singleton registrar instance. static WindowClassRegistrar* GetInstance() { if (!instance_) { instance_ = new WindowClassRegistrar(); } return instance_; } // Returns the name of the window class, registering the class if it hasn't // previously been registered. const wchar_t* GetWindowClass(); // Unregisters the window class. Should only be called if there are no // instances of the window. void UnregisterWindowClass(); private: WindowClassRegistrar() = default; static WindowClassRegistrar* instance_; bool class_registered_ = false; }; WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; const wchar_t* WindowClassRegistrar::GetWindowClass() { if (!class_registered_) { WNDCLASS window_class{}; window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); window_class.lpszClassName = kWindowClassName; window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = GetModuleHandle(nullptr); window_class.hIcon = LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); window_class.hbrBackground = 0; window_class.lpszMenuName = nullptr; window_class.lpfnWndProc = Win32Window::WndProc; RegisterClass(&window_class); class_registered_ = true; } return kWindowClassName; } void WindowClassRegistrar::UnregisterWindowClass() { UnregisterClass(kWindowClassName, nullptr); class_registered_ = false; } Win32Window::Win32Window() { ++g_active_window_count; } Win32Window::~Win32Window() { --g_active_window_count; Destroy(); } bool Win32Window::Create(const std::wstring& title, const Point& origin, const Size& size) { Destroy(); const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = {static_cast(origin.x), static_cast(origin.y)}; HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / 96.0; HWND window = CreateWindow( window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); if (!window) { return false; } UpdateTheme(window); return OnCreate(); } bool Win32Window::Show() { return ShowWindow(window_handle_, SW_SHOWNORMAL); } // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { if (message == WM_NCCREATE) { auto window_struct = reinterpret_cast(lparam); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window* that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); } return DefWindowProc(window, message, wparam, lparam); } LRESULT Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { switch (message) { case WM_DESTROY: window_handle_ = nullptr; Destroy(); if (quit_on_close_) { PostQuitMessage(0); } return 0; case WM_DPICHANGED: { auto newRectSize = reinterpret_cast(lparam); LONG newWidth = newRectSize->right - newRectSize->left; LONG newHeight = newRectSize->bottom - newRectSize->top; SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } case WM_SIZE: { RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); } return 0; } case WM_ACTIVATE: if (child_content_ != nullptr) { SetFocus(child_content_); } return 0; case WM_DWMCOLORIZATIONCOLORCHANGED: UpdateTheme(hwnd); return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); } void Win32Window::Destroy() { OnDestroy(); if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; } if (g_active_window_count == 0) { WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); } } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA)); } void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); SetFocus(child_content_); } RECT Win32Window::GetClientArea() { RECT frame; GetClientRect(window_handle_, &frame); return frame; } HWND Win32Window::GetHandle() { return window_handle_; } void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } bool Win32Window::OnCreate() { // No-op; provided for subclasses. return true; } void Win32Window::OnDestroy() { // No-op; provided for subclasses. } void Win32Window::UpdateTheme(HWND const window) { DWORD light_mode; DWORD light_mode_size = sizeof(light_mode); LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, nullptr, &light_mode, &light_mode_size); if (result == ERROR_SUCCESS) { BOOL enable_dark_mode = light_mode == 0; DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, &enable_dark_mode, sizeof(enable_dark_mode)); } } ================================================ FILE: simple_live_app/windows/runner/win32_window.h ================================================ #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ #include #include #include #include // A class abstraction for a high DPI-aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling class Win32Window { public: struct Point { unsigned int x; unsigned int y; Point(unsigned int x, unsigned int y) : x(x), y(y) {} }; struct Size { unsigned int width; unsigned int height; Size(unsigned int width, unsigned int height) : width(width), height(height) {} }; Win32Window(); virtual ~Win32Window(); // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a // consistent size this function will scale the inputted width and height as // as appropriate for the default monitor. The window is invisible until // |Show| is called. Returns true if the window was created successfully. bool Create(const std::wstring& title, const Point& origin, const Size& size); // Show the current window. Returns true if the window was successfully shown. bool Show(); // Release OS resources associated with window. void Destroy(); // Inserts |content| into the window tree. void SetChildContent(HWND content); // Returns the backing Window handle to enable clients to set icon and other // window properties. Returns nullptr if the window has been destroyed. HWND GetHandle(); // If true, closing this window will quit the application. void SetQuitOnClose(bool quit_on_close); // Return a RECT representing the bounds of the current client area. RECT GetClientArea(); protected: // Processes and route salient window messages for mouse handling, // size change and DPI. Delegates handling of these to member overloads that // inheriting classes can handle. virtual LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Called when CreateAndShow is called, allowing subclass window-related // setup. Subclasses should return false if setup fails. virtual bool OnCreate(); // Called when Destroy is called. virtual void OnDestroy(); private: friend class WindowClassRegistrar; // OS callback called by message pump. Handles the WM_NCCREATE message which // is passed when the non-client area is being created and enables automatic // non-client DPI scaling so that the non-client area automatically // responds to changes in DPI. All other messages are handled by // MessageHandler. static LRESULT CALLBACK WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; // Update the window frame's theme to match the system theme. static void UpdateTheme(HWND const window); bool quit_on_close_ = false; // window handle for top level window. HWND window_handle_ = nullptr; // window handle for hosted content. HWND child_content_ = nullptr; }; #endif // RUNNER_WIN32_WINDOW_H_ ================================================ FILE: simple_live_console/.gitignore ================================================ # https://dart.dev/guides/libraries/private-files # Created by `dart pub` .dart_tool/ build/ pubspec.lock ================================================ FILE: simple_live_console/.vscode/launch.json ================================================ { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Dart & Flutter", "request": "launch", "type": "dart", "program": "bin/simple_live_console.dart", "args": [ "-d", "https://www.douyu.com/1126960" ] } ] } ================================================ FILE: simple_live_console/CHANGELOG.md ================================================ ## 1.0.0 - Initial version. ================================================ FILE: simple_live_console/README.md ================================================ # simple_live_console 基于simple_live_core的控制台程序。 输入直播间播放直链获取信息及播放地址: ``` simple_live.exe -i [URL] ``` 输入直播间链接获取弹幕: ``` simple_live.exe -d [URL] ``` ================================================ FILE: simple_live_console/analysis_options.yaml ================================================ # This file configures the static analysis results for your project (errors, # warnings, and lints). # # This enables the 'recommended' set of lints from `package:lints`. # This set helps identify many issues that may lead to problems when running # or consuming Dart code, and enforces writing Dart using a single, idiomatic # style and format. # # If you want a smaller set of lints you can change this to specify # 'package:lints/core.yaml'. These are just the most critical lints # (the recommended set includes the core lints). # The core lints are also what is used by pub.dev for scoring packages. include: package:lints/recommended.yaml # Uncomment the following section to specify additional rules. # linter: # rules: # - camel_case_types # analyzer: # exclude: # - path/to/excluded/files/** # For more information about the core and recommended set of lints, see # https://dart.dev/go/core-lints # For additional information about configuring this file, see # https://dart.dev/guides/language/analysis-options ================================================ FILE: simple_live_console/bin/simple_live_console.dart ================================================ import 'dart:io'; import 'package:simple_live_core/simple_live_core.dart'; void main(List arguments) async { CoreLog.enableLog = false; if (arguments.isEmpty) { printHelp(); return; } var action = arguments.first.toLowerCase().replaceAll("-", ""); if (arguments.length < 2) { print("错误的参数"); printHelp(); return; } var url = arguments[1]; if (url.isEmpty) { print("[URL]不能为空"); printHelp(); return; } if (action == "i") { await printInfo(url); } else if (action == "d") { printDanmaku(url); } else if (action == "h") { printHelp(); } else { print("未知指令:$action"); printHelp(); } } void printHelp() { print("-i [URL] :获取直播间信息及播放直链"); print("-d [URL] :持续输出直播间弹幕"); } Future printInfo(String url) async { var urlInfo = parseUrl(url); LiveSite site = urlInfo.first; var id = urlInfo.last; var detail = await site.getRoomDetail(roomId: id); print("来源:${site.name}"); print("房间号:${detail.roomId}"); print("房间标题:${detail.title}"); print("直播用户:${detail.userName}"); print("人气值:${detail.online}"); print("状态:${(detail.status ? "直播中" : "未开播")}"); if (detail.status) { print("可用清晰度:"); var quality = await site.getPlayQualites(detail: detail); for (int i = 0; i < quality.length; i++) { print("【${i + 1}】${quality[i].quality}"); } print("请输入【】内数字,获取对应清晰度的直链"); var input = stdin.readLineSync() ?? ""; print("正在获取直链..."); var index = int.tryParse(input) ?? 0; if (index > 0) { var url = await site.getPlayUrls(detail: detail, quality: quality[index - 1]); for (int i = 0; i < url.urls.length; i++) { print("线路${i + 1}:\r\n${url.urls[i]}"); } } } } Future printDanmaku(String url) async { var urlInfo = parseUrl(url); LiveSite site = urlInfo.first; var id = urlInfo.last; var detail = await site.getRoomDetail(roomId: id); print("来源:${site.name}"); print("房间号:${detail.roomId}"); print("房间标题:${detail.title}"); print("直播用户:${detail.userName}"); print("状态:${(detail.status ? "直播中" : "未开播")}"); var danmaku = site.getDanmaku(); danmaku.onMessage = (LiveMessage e) { if (e.type == LiveMessageType.online) { print("-----人气值:${e.data}-----"); } else if (e.type == LiveMessageType.chat) { print("${e.userName}:${e.message}"); } }; danmaku.onClose = (String e) { print(e); }; print("【开始获取弹幕】"); await danmaku.start(detail.danmakuData); await Future(() {}); } List parseUrl(String url) { if (url.contains("bilibili.com")) { var id = RegExp(r"bilibili\.com/([\d|\w]+)").firstMatch(url)?.group(1) ?? ""; return [BiliBiliSite(), id]; } if (url.contains("huya.com")) { var id = RegExp(r"huya\.com/([\d|\w]+)").firstMatch(url)?.group(1) ?? ""; return [HuyaSite(), id]; } if (url.contains("douyu.com")) { var id = RegExp(r"douyu\.com/([\d|\w]+)").firstMatch(url)?.group(1) ?? ""; return [DouyuSite(), id]; } if (url.contains("live.douyin.com")) { var id = RegExp(r"live\.douyin\.com/([\d|\w]+)").firstMatch(url)?.group(1) ?? ""; return [DouyinSite(), id]; } throw Exception("链接解析失败"); } ================================================ FILE: simple_live_console/pubspec.yaml ================================================ name: simple_live_console description: A sample command-line application. version: 1.0.0 publish_to: "none" # repository: https://github.com/my_org/my_repo environment: sdk: '>=3.10.0' dependencies: simple_live_core: path: ../simple_live_core dev_dependencies: lints: ^2.0.0 test: ^1.21.0 ================================================ FILE: simple_live_console/test/all_live_console_test.dart ================================================ import 'package:test/test.dart'; void main() { test('calculate', () {}); } ================================================ FILE: simple_live_core/.gitignore ================================================ # https://dart.dev/guides/libraries/private-files # Created by `dart pub` .dart_tool/ # Avoid committing pubspec.lock for library packages; see # https://dart.dev/guides/libraries/private-files#pubspeclock. pubspec.lock .fvm/ ================================================ FILE: simple_live_core/.vscode/launch.json ================================================ { // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "simple_live_core", "request": "launch", "type": "dart", "program": "example/simple_live_core_example.dart" } ] } ================================================ FILE: simple_live_core/CHANGELOG.md ================================================ ## 1.0.0 - Initial version. ================================================ FILE: simple_live_core/README.md ================================================ # simple_live_core 项目核心库,实现获取各个网站的信息及弹幕。 ================================================ FILE: simple_live_core/analysis_options.yaml ================================================ # This file configures the static analysis results for your project (errors, # warnings, and lints). # # This enables the 'recommended' set of lints from `package:lints`. # This set helps identify many issues that may lead to problems when running # or consuming Dart code, and enforces writing Dart using a single, idiomatic # style and format. # # If you want a smaller set of lints you can change this to specify # 'package:lints/core.yaml'. These are just the most critical lints # (the recommended set includes the core lints). # The core lints are also what is used by pub.dev for scoring packages. include: package:lints/recommended.yaml # Uncomment the following section to specify additional rules. # linter: # rules: # - camel_case_types # analyzer: # exclude: # - path/to/excluded/files/** # For more information about the core and recommended set of lints, see # https://dart.dev/go/core-lints # For additional information about configuring this file, see # https://dart.dev/guides/language/analysis-options ================================================ FILE: simple_live_core/example/simple_live_core_example.dart ================================================ void main() async { print('Hello, World!'); } ================================================ FILE: simple_live_core/lib/simple_live_core.dart ================================================ library simple_live_core; export 'src/interface/live_site.dart'; export 'src/interface/live_danmaku.dart'; export 'src/huya_site.dart'; export 'src/bilibili_site.dart'; export 'src/douyu_site.dart'; export 'src/douyin_site.dart'; export 'src/common/core_log.dart'; export 'src/model/live_message.dart'; export 'src/danmaku/bilibili_danmaku.dart'; export 'src/danmaku/douyu_danmaku.dart'; export 'src/danmaku/huya_danmaku.dart'; export 'src/danmaku/douyin_danmaku.dart'; export 'src/model/live_category_result.dart'; export 'src/model/live_category.dart'; export 'src/model/live_play_quality.dart'; export 'src/model/live_room_detail.dart'; export 'src/model/live_room_item.dart'; export 'src/model/live_search_result.dart'; export 'src/model/live_anchor_item.dart'; export 'src/model/live_play_url.dart'; ================================================ FILE: simple_live_core/lib/src/bilibili_site.dart ================================================ import 'dart:convert'; import 'package:crypto/crypto.dart'; import 'package:simple_live_core/src/common/convert_helper.dart'; import 'package:simple_live_core/src/common/http_client.dart'; import 'package:simple_live_core/src/danmaku/bilibili_danmaku.dart'; import 'package:simple_live_core/src/interface/live_danmaku.dart'; import 'package:simple_live_core/src/interface/live_site.dart'; import 'package:simple_live_core/src/model/live_anchor_item.dart'; import 'package:simple_live_core/src/model/live_category.dart'; import 'package:simple_live_core/src/model/live_message.dart'; import 'package:simple_live_core/src/model/live_play_url.dart'; import 'package:simple_live_core/src/model/live_room_item.dart'; import 'package:simple_live_core/src/model/live_search_result.dart'; import 'package:simple_live_core/src/model/live_room_detail.dart'; import 'package:simple_live_core/src/model/live_play_quality.dart'; import 'package:simple_live_core/src/model/live_category_result.dart'; class BiliBiliSite implements LiveSite { @override String id = "bilibili"; @override String name = "哔哩哔哩直播"; String cookie = ""; int userId = 0; @override LiveDanmaku getDanmaku() => BiliBiliDanmaku(); static const String kDefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"; static const String kDefaultReferer = "https://live.bilibili.com/"; String buvid3 = ""; String buvid4 = ""; String accessId = ""; Future> getHeader() async { if (buvid3.isEmpty) { var buvidInfo = await getBuvid(); buvid3 = buvidInfo["b_3"] ?? ""; buvid4 = buvidInfo["b_4"] ?? ""; } return cookie.isEmpty ? { "user-agent": kDefaultUserAgent, "referer": kDefaultReferer, "cookie": 'buvid3=$buvid3;buvid4=$buvid4;', } : { "cookie": cookie.contains("buvid3") ? cookie : "$cookie;buvid3=$buvid3;buvid4=$buvid4;", "user-agent": kDefaultUserAgent, "referer": kDefaultReferer, }; } @override Future> getCategores() async { List categories = []; var result = await HttpClient.instance.getJson( "https://api.live.bilibili.com/room/v1/Area/getList", queryParameters: { "need_entrance": 1, "parent_id": 0, }, header: await getHeader(), ); for (var item in result["data"]) { List subs = []; for (var subItem in item["list"]) { var subCategory = LiveSubCategory( id: subItem["id"].toString(), name: asT(subItem["name"]) ?? "", parentId: asT(subItem["parent_id"]) ?? "", pic: "${asT(subItem["pic"]) ?? ""}@100w.png", ); subs.add(subCategory); } var category = LiveCategory( children: subs, id: item["id"].toString(), name: asT(item["name"]) ?? "", ); categories.add(category); } return categories; } @override Future getCategoryRooms(LiveSubCategory category, {int page = 1}) async { const baseUrl = "https://api.live.bilibili.com/xlive/web-interface/v1/second/getList"; var url = "$baseUrl?platform=web&parent_area_id=${category.parentId}&area_id=${category.id}&sort_type=&page=$page&w_webid=${await getAccessId()}"; var queryParams = await getWbiSign(url); var result = await HttpClient.instance.getJson( baseUrl, queryParameters: queryParams, header: await getHeader(), ); var hasMore = result["data"]["has_more"] == 1; var items = []; for (var item in result["data"]["list"]) { var roomItem = LiveRoomItem( roomId: item["roomid"].toString(), title: item["title"].toString(), cover: "${item["cover"]}@400w.jpg", userName: item["uname"].toString(), online: int.tryParse(item["online"].toString()) ?? 0, ); items.add(roomItem); } return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future> getPlayQualites( {required LiveRoomDetail detail}) async { List qualities = []; var result = await HttpClient.instance.getJson( "https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo", queryParameters: { "room_id": detail.roomId, "protocol": "0,1", "format": "0,1,2", "codec": "0,1", "platform": "web", }, header: await getHeader(), ); var qualitiesMap = {}; for (var item in result["data"]["playurl_info"]["playurl"]["g_qn_desc"]) { qualitiesMap[int.tryParse(item["qn"].toString()) ?? 0] = item["desc"].toString(); } for (var item in result["data"]["playurl_info"]["playurl"]["stream"][0] ["format"][0]["codec"][0]["accept_qn"]) { var qualityItem = LivePlayQuality( quality: qualitiesMap[item] ?? "未知清晰度", data: item, ); qualities.add(qualityItem); } return qualities; } @override Future getPlayUrls( {required LiveRoomDetail detail, required LivePlayQuality quality}) async { List urls = []; var result = await HttpClient.instance.getJson( "https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo", queryParameters: { "room_id": detail.roomId, "protocol": "0,1", "format": "0,2", "codec": "0", "platform": "web", "qn": quality.data, }, header: await getHeader(), ); var streamList = result["data"]["playurl_info"]["playurl"]["stream"]; for (var streamItem in streamList) { var formatList = streamItem["format"]; for (var formatItem in formatList) { var codecList = formatItem["codec"]; for (var codecItem in codecList) { var urlList = codecItem["url_info"]; var baseUrl = codecItem["base_url"].toString(); for (var urlItem in urlList) { urls.add( "${urlItem["host"]}$baseUrl${urlItem["extra"]}", ); } } } } // 对链接进行排序,包含mcdn的在后 urls.sort((a, b) { if (a.contains("mcdn")) { return 1; } else { return -1; } }); return LivePlayUrl( urls: urls, headers: { "referer": "https://live.bilibili.com", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188" }, ); } @override Future getRecommendRooms({int page = 1}) async { const baseUrl = "https://api.live.bilibili.com/xlive/web-interface/v1/second/getListByArea"; var url = "$baseUrl?platform=web&sort=online&page_size=30&page=$page"; var queryParams = await getWbiSign(url); var result = await HttpClient.instance.getJson( baseUrl, queryParameters: queryParams, header: await getHeader(), ); var hasMore = (result["data"]["list"] as List).isNotEmpty; var items = []; for (var item in result["data"]["list"]) { var roomItem = LiveRoomItem( roomId: item["roomid"].toString(), title: item["title"].toString(), cover: "${item["cover"]}@400w.jpg", userName: item["uname"].toString(), online: int.tryParse(item["online"].toString()) ?? 0, ); items.add(roomItem); } return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future getRoomDetail({required String roomId}) async { var roomInfo = await getRoomInfo(roomId: roomId); var realRoomId = roomInfo["room_info"]["room_id"].toString(); const danmuInfoBaseUrl = "https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo"; var danmuInfoUrl = "$danmuInfoBaseUrl?id=$realRoomId"; var queryParams = await getWbiSign(danmuInfoUrl); var roomDanmakuResult = await HttpClient.instance.getJson( danmuInfoBaseUrl, queryParameters: queryParams, header: await getHeader(), ); List serverHosts = (roomDanmakuResult["data"]["host_list"] as List) .map((e) => e["host"].toString()) .toList(); //var buvid = await getBuvid(); // 从 roomInfo 中提取 live_start_time String? liveStartTime = roomInfo["room_info"]?["live_start_time"]?.toString(); // 计算开播时长并打印到控制台 (参考斗鱼的实现) if (liveStartTime != null && liveStartTime.isNotEmpty && liveStartTime != "0") { // 检查是否为0,0可能表示未开播或无此信息 try { int startTimeStamp = int.parse(liveStartTime); int currentTimeStamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; int durationInSeconds = currentTimeStamp - startTimeStamp; int hours = durationInSeconds ~/ 3600; int minutes = (durationInSeconds % 3600) ~/ 60; int seconds = durationInSeconds % 60; String formattedDuration = '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; print('Bilibili直播间 $roomId 开播时长: $formattedDuration'); } catch (e) { print('计算 Bilibili 开播时长出错: $e'); } } return LiveRoomDetail( roomId: realRoomId, title: roomInfo["room_info"]["title"].toString(), cover: roomInfo["room_info"]["cover"].toString(), userName: roomInfo["anchor_info"]["base_info"]["uname"].toString(), userAvatar: "${roomInfo["anchor_info"]["base_info"]["face"]}@100w.jpg", online: asT(roomInfo["room_info"]["online"]) ?? 0, status: (asT(roomInfo["room_info"]["live_status"]) ?? 0) == 1, url: "https://live.bilibili.com/$roomId", introduction: roomInfo["room_info"]["description"].toString(), notice: "", danmakuData: BiliBiliDanmakuArgs( roomId: int.tryParse(realRoomId) ?? 0, uid: userId, token: roomDanmakuResult["data"]["token"].toString(), serverHost: serverHosts.isNotEmpty ? serverHosts.first : "broadcastlv.chat.bilibili.com", buvid: buvid3, cookie: cookie, ), showTime: liveStartTime, // 将 liveStartTime 赋值给 showTime 字段 ); } Future> getRoomInfo({required String roomId}) async { var url = "https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=$roomId"; var queryParams = await getWbiSign(url); var result = await HttpClient.instance.getJson( "https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom", queryParameters: queryParams, header: await getHeader(), ); print("【B站接口返回】roomId=$roomId, result=$result"); return result["data"]; } @override Future searchRooms(String keyword, {int page = 1}) async { var result = await HttpClient.instance.getJson( "https://api.bilibili.com/x/web-interface/search/type?context=&search_type=live&cover_type=user_cover", queryParameters: { "order": "", "keyword": keyword, "category_id": "", "__refresh__": "", "_extra": "", "highlight": 0, "single_column": 0, "page": page }, header: await getHeader(), ); var items = []; for (var item in result["data"]["result"]["live_room"] ?? []) { var title = item["title"].toString(); //移除title中的标签 title = title.replaceAll(RegExp(r"<.*?em.*?>"), ""); var roomItem = LiveRoomItem( roomId: item["roomid"].toString(), title: title, cover: "https:${item["cover"]}@400w.jpg", userName: item["uname"].toString(), online: int.tryParse(item["online"].toString()) ?? 0, ); items.add(roomItem); } return LiveSearchRoomResult(hasMore: items.length >= 40, items: items); } @override Future searchAnchors(String keyword, {int page = 1}) async { var result = await HttpClient.instance.getJson( "https://api.bilibili.com/x/web-interface/search/type?context=&search_type=live_user&cover_type=user_cover", queryParameters: { "order": "", "keyword": keyword, "category_id": "", "__refresh__": "", "_extra": "", "highlight": 0, "single_column": 0, "page": page }, header: await getHeader(), ); var items = []; for (var item in result["data"]["result"] ?? []) { var uname = item["uname"].toString(); //移除title中的标签 uname = uname.replaceAll(RegExp(r"<.*?em.*?>"), ""); var anchorItem = LiveAnchorItem( roomId: item["roomid"].toString(), avatar: "https:${item["uface"]}@400w.jpg", userName: uname, liveStatus: item["is_live"], ); items.add(anchorItem); } return LiveSearchAnchorResult(hasMore: items.length >= 40, items: items); } @override Future getLiveStatus({required String roomId}) async { var result = await HttpClient.instance.getJson( "https://api.live.bilibili.com/room/v1/Room/get_info", queryParameters: { "room_id": roomId, }, header: await getHeader(), ); return (asT(result["data"]["live_status"]) ?? 0) == 1; } @override Future> getSuperChatMessage( {required String roomId}) async { var result = await HttpClient.instance.getJson( "https://api.live.bilibili.com/av/v1/SuperChat/getMessageList", queryParameters: { "room_id": roomId, }, header: await getHeader(), ); List ls = []; for (var item in result["data"]?["list"] ?? []) { var message = LiveSuperChatMessage( backgroundBottomColor: item["background_bottom_color"].toString(), backgroundColor: item["background_color"].toString(), endTime: DateTime.fromMillisecondsSinceEpoch( item["end_time"] * 1000, ), face: "${item["user_info"]["face"]}@200w.jpg", message: item["message"].toString(), price: item["price"], startTime: DateTime.fromMillisecondsSinceEpoch( item["start_time"] * 1000, ), userName: item["user_info"]["uname"].toString(), ); ls.add(message); } return ls; } /// 获取 buvid3 和 buvid4 /// 返回buvid3和buvid4 /// ``` json /// { /// "b_3": "buvid3", /// "b_4": "buvid4", /// } /// ``` Future getBuvid() async { try { if (cookie.contains("buvid3")) { return { "b_3": RegExp(r"buvid3=(.*?);").firstMatch(cookie)?.group(1) ?? "", "b_4": RegExp(r"buvid4=(.*?);").firstMatch(cookie)?.group(1) ?? "", }; } var result = await HttpClient.instance.getJson( "https://api.bilibili.com/x/frontend/finger/spi", queryParameters: {}, header: { "user-agent": kDefaultUserAgent, "referer": kDefaultReferer, "cookie": cookie, }, ); return result["data"]; } catch (e) { return { "b_3": "", "b_4": "", }; } } static String kImgKey = ''; static String kSubKey = ''; static const List mixinKeyEncTab = [ 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11, 36, 20, 34, 44, 52 ]; Future<(String, String)> getWbiKeys() async { if (kImgKey.isNotEmpty && kSubKey.isNotEmpty) { return (kImgKey, kSubKey); } // 获取最新的 img_key 和 sub_key var resp = await HttpClient.instance.getJson( 'https://api.bilibili.com/x/web-interface/nav', header: await getHeader(), ); var imgUrl = resp["data"]["wbi_img"]["img_url"].toString(); var subUrl = resp["data"]["wbi_img"]["sub_url"].toString(); var imgKey = imgUrl.substring(imgUrl.lastIndexOf('/') + 1).split('.').first; var subKey = subUrl.substring(subUrl.lastIndexOf('/') + 1).split('.').first; kImgKey = imgKey; kSubKey = subKey; return (imgKey, subKey); } String getMixinKey(String origin) { // 对 imgKey 和 subKey 进行字符顺序打乱编码 return mixinKeyEncTab.fold("", (s, i) => s + origin[i]).substring(0, 32); } Future> getWbiSign(String url) async { var (imgKey, subKey) = await getWbiKeys(); // 为请求参数进行 wbi 签名 var mixinKey = getMixinKey(imgKey + subKey); var currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000; var queryParams = Map.from(Uri.parse(url).queryParameters); queryParams["wts"] = currentTime.toString(); // 添加 wts 字段 //按照 key 重排参数 Map map = {}; var sortedKeys = queryParams.keys.toList()..sort(); for (var key in sortedKeys) { var value = queryParams[key]!; // 过滤 value 中的 "!'()*" 字符 map[key] = value .toString() .split('') .where((c) => "!'()*".contains(c) == false) .join(''); } var query = map.keys .map((key) => "$key=${Uri.encodeQueryComponent(map[key]!)}") .join("&"); var wbiSign = md5.convert(utf8.encode("$query$mixinKey")).toString(); queryParams["w_rid"] = wbiSign; return queryParams; } Future getAccessId() async { if (accessId.isNotEmpty) { return accessId; } // 获取 access_id var resp = await HttpClient.instance.getText( "https://live.bilibili.com/lol", queryParameters: {}, header: await getHeader(), ); var id = RegExp(r'"access_id":"(.*?)"') .firstMatch(resp) ?.group(1) ?.replaceAll("\\", ""); accessId = id ?? ""; return accessId; } } ================================================ FILE: simple_live_core/lib/src/common/binary_writer.dart ================================================ import 'dart:typed_data'; class BinaryWriter { List buffer; int position = 0; BinaryWriter(this.buffer); int get length => buffer.length; void writeBytes(List list) { buffer.addAll(list); position += list.length; } void writeInt(int value, int len, {Endian endian = Endian.big}) { var b = Uint8List(len).buffer; var bytes = ByteData.view(b); if (len == 1) { //写入byte bytes.setUint8(0, value.toUnsigned(8)); } if (len == 2) { bytes.setInt16(0, value, endian); } if (len == 4) { bytes.setInt32(0, value, endian); } if (len == 8) { bytes.setInt64(0, value, endian); } buffer.addAll(bytes.buffer.asUint8List()); position += len; } void writeDouble(double value, int len, {Endian endian = Endian.big}) { var b = Uint8List(len).buffer; var bytes = ByteData.view(b); if (len == 4) { bytes.setFloat32(0, value, endian); } if (len == 8) { bytes.setFloat64(0, value, endian); } buffer.addAll(bytes.buffer.asUint8List()); position += len; } } class BinaryReader { Uint8List buffer; int position = 0; BinaryReader(this.buffer); int get length => buffer.length; /// 从当前流中读取下一个字节,并使流的当前位置提升 1 个字节 /// 返回下一个字节(0-255) int read() { var byte = buffer[position]; position += 1; return byte; } /// 从当前流中读取指定长度的字节整数,并使流的当前位置提升指定长度。 /// [len] 指定长度 /// len=1为int8,2为int16,4为int32,8为int64。dart中统一为int类型 /// 返回整数 int readInt(int len, {Endian endian = Endian.big}) { var result = 0; // if (len == 1) { // result = buffer[position]; // position += len; // return result; // } var bytes = Uint8List.fromList(buffer.getRange(position, position + len).toList()); var byteBuffer = bytes.buffer; var data = ByteData.view(byteBuffer); if (len == 1) { result = data.getUint8(0); } if (len == 2) { result = data.getInt16(0, endian); } if (len == 4) { result = data.getInt32(0, endian); } if (len == 8) { result = data.getInt64(0, endian); } position += len; return result; } /// 读取字节 /// int长度=1 int readByte({Endian endian = Endian.big}) { return readInt(1, endian: endian); } /// 读取 /// int长度=2 int readShort({Endian endian = Endian.big}) { return readInt(2, endian: endian); } /// 读取字节 /// int长度=4 int readInt32({Endian endian = Endian.big}) { return readInt(4, endian: endian); } /// 读取字节 /// int长度=8 int readLong({Endian endian = Endian.big}) { return readInt(8, endian: endian); } /// 从当前流中读取指定长度的字节数组,并使流的当前位置提升指定长度。 /// [len] 指定长度 /// 返回字节数组 Uint8List readBytes(int len) { var bytes = Uint8List.fromList(buffer.getRange(position, position + len).toList()); position += len; return bytes; } /// 从当前流中读取指定长度的字节浮点数,并使流的当前位置提升指定长度。 /// [len] 指定长度 /// len=4为float,8为double。dart中统一为double类型 /// 返回浮点数 double readFloat(int len, {Endian endian = Endian.big}) { var result = 0.0; var bytes = Uint8List.fromList(buffer.getRange(position, position + len).toList()); var byteBuffer = bytes.buffer; var data = ByteData.view(byteBuffer); if (len == 4) { result = data.getFloat32(0, endian); } if (len == 8) { result = data.getFloat64(0, endian); } position += len; return result; } } ================================================ FILE: simple_live_core/lib/src/common/convert_helper.dart ================================================ T? asT(dynamic value) { if (value is T) { return value; } return null; } ================================================ FILE: simple_live_core/lib/src/common/core_error.dart ================================================ class CoreError extends Error { /// 错误码 final int statusCode; /// 错误信息 final String message; CoreError( this.message, { this.statusCode = 0, }); @override String toString() { if (statusCode != 0) { return statusCodeToString(statusCode); } return message; } String statusCodeToString(int statusCode) { switch (statusCode) { case 400: return "错误的请求(400)"; case 401: return "无权限访问资源(401)"; case 403: return "无权限访问资源(403)"; case 404: return "服务器找不到请求的资源(404)"; case 500: return "服务器出现错误(500)"; case 502: return "服务器出现错误(502)"; case 503: return "服务器出现错误(503)"; default: return "连接服务器失败,请稍后再试($statusCode)"; } } } ================================================ FILE: simple_live_core/lib/src/common/core_log.dart ================================================ import 'package:logger/logger.dart'; enum RequestLogType { /// 输出所有请求信息 /// 包括请求的URL,请求的参数,请求的头,请求的体,响应的头,响应的内容,耗时 all, /// 简洁的输出 /// 仅输出请求的URL和响应的状态码 short, /// 不输出请求信息 none, } class CoreLog { /// 是否启用日志 static bool enableLog = true; /// 请求日志模式 static RequestLogType requestLogType = RequestLogType.all; static Function(Level, String)? onPrintLog; static Logger logger = Logger( printer: PrettyPrinter( methodCount: 0, errorMethodCount: 8, lineLength: 120, colors: true, printEmojis: true, ), ); static void d(String message) { if (!enableLog) { return; } onPrintLog?.call(Level.debug, message); if (onPrintLog == null) { logger.d("${DateTime.now().toString()}\n$message"); } } static void i(String message) { if (!enableLog) { return; } onPrintLog?.call(Level.info, message); if (onPrintLog == null) { logger.i("${DateTime.now().toString()}\n$message"); } } static void e(String message, StackTrace stackTrace) { if (!enableLog) { return; } onPrintLog?.call(Level.error, message); if (onPrintLog == null) { logger.e("${DateTime.now().toString()}\n$message", stackTrace: stackTrace); } } static void error(e) { if (!enableLog) { return; } onPrintLog?.call(Level.error, e.toString()); if (onPrintLog == null) { logger.e( "${DateTime.now().toString()}\n${e.toString()}", error: e, stackTrace: (e is Error) ? e.stackTrace : StackTrace.current, ); } } static void w(String message) { if (!enableLog) { return; } onPrintLog?.call(Level.warning, message); if (onPrintLog == null) { logger.w("${DateTime.now().toString()}\n$message"); } } } ================================================ FILE: simple_live_core/lib/src/common/custom_interceptor.dart ================================================ import 'package:dio/dio.dart'; import 'core_log.dart'; class CustomInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { options.extra["ts"] = DateTime.now().millisecondsSinceEpoch; if (CoreLog.requestLogType == RequestLogType.all) { CoreLog.i( '''[HTTP Request] [${options.method}] Request URL:${options.uri} Request Query:${options.queryParameters} Request Data:${options.data} Request Headers:${options.headers}''', ); } else if (CoreLog.requestLogType == RequestLogType.short) { CoreLog.i("[HTTP Request] [${options.method}] ${options.uri}"); } super.onRequest(options, handler); } @override void onError(DioException err, ErrorInterceptorHandler handler) { var time = DateTime.now().millisecondsSinceEpoch - err.requestOptions.extra["ts"]; if (CoreLog.requestLogType == RequestLogType.all) { CoreLog.e('''[HTTP Error] [${err.type}] [Time:${time}ms] ${err.message} Request Method:${err.requestOptions.method} Response Code:${err.response?.statusCode} Request URL:${err.requestOptions.uri} Request Query:${err.requestOptions.queryParameters} Request Data:${err.requestOptions.data} Request Headers:${err.requestOptions.headers} Response Headers:${err.response?.headers.map} Response Data:${err.response?.data}''', err.stackTrace); } else { CoreLog.e( "[HTTP Error] [${err.type}] [Time:${time}ms]\n[${err.response?.statusCode}] ${err.requestOptions.uri}", err.stackTrace, ); } super.onError(err, handler); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { var time = DateTime.now().millisecondsSinceEpoch - response.requestOptions.extra["ts"]; if (CoreLog.requestLogType == RequestLogType.all) { CoreLog.i( '''[HTTP Response] [time:${time}ms] Request Method:${response.requestOptions.method} Request Code:${response.statusCode} Request URL:${response.requestOptions.uri} Request Query:${response.requestOptions.queryParameters} Request Data:${response.requestOptions.data} Request Headers:${response.requestOptions.headers} Response Headers:${response.headers.map} Response Data:${response.data}''', ); } else if (CoreLog.requestLogType == RequestLogType.short) { CoreLog.i( "[HTTP Response] [time:${time}ms] [${response.statusCode}] ${response.requestOptions.uri}", ); } super.onResponse(response, handler); } } ================================================ FILE: simple_live_core/lib/src/common/http_client.dart ================================================ import 'package:simple_live_core/src/common/core_error.dart'; import 'package:dio/dio.dart'; import 'custom_interceptor.dart'; class HttpClient { static HttpClient? _httpUtil; static HttpClient get instance { _httpUtil ??= HttpClient(); return _httpUtil!; } late Dio dio; HttpClient() { dio = Dio( BaseOptions( connectTimeout: Duration(seconds: 20), receiveTimeout: Duration(seconds: 20), sendTimeout: Duration(seconds: 20), ), ); dio.interceptors.add(CustomInterceptor()); } /// Get请求,返回String /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future getText( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.plain, headers: header, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw CoreError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw CoreError("发送GET请求失败"); } } } /// Get请求,返回Map /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future getJson( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.json, headers: header, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw CoreError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw CoreError("发送GET请求失败"); } } } /// Post请求,返回Map /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [data] 内容 /// * [cancel] 任务取消Token Future postJson( String url, { Map? queryParameters, dynamic data, Map? header, bool formUrlEncoded = false, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; data ??= {}; var result = await dio.post( url, queryParameters: queryParameters, data: data, options: Options( responseType: ResponseType.json, headers: header, contentType: formUrlEncoded ? Headers.formUrlEncodedContentType : null, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw CoreError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw CoreError("发送POST请求失败"); } } } /// Head请求,返回Response /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future head( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.head( url, queryParameters: queryParameters, options: Options( headers: header, receiveDataWhenStatusError: true, ), cancelToken: cancel, ); return result; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { //throw CoreError(e.message, statusCode: e.response?.statusCode ?? 0); return e.response!; } else { throw CoreError("发送HEAD请求失败"); } } } } ================================================ FILE: simple_live_core/lib/src/common/web_socket_util.dart ================================================ import 'dart:async'; import 'package:web_socket_channel/io.dart'; enum SocketStatus { connected, failed, closed, } class WebScoketUtils { SocketStatus status = SocketStatus.closed; /// 链接 final String url; /// 备用链接 final String? backupUrl; /// 心跳时间 final int heartBeatTime; /// 接收到信息 final Function(dynamic)? onMessage; /// 连接关闭 final Function(String msg)? onClose; /// 尝试重连 final Function()? onReconnect; /// 准备就绪 final Function()? onReady; /// 心跳 final Function()? onHeartBeat; /// 请求头 Map? headers; WebScoketUtils({ required this.url, required this.heartBeatTime, this.onMessage, this.onClose, this.onReconnect, this.onReady, this.onHeartBeat, this.headers, this.backupUrl, }); IOWebSocketChannel? webSocket; Timer? heartBeatTimer; /// 重连次数 int reconnectTime = 0; Timer? reconnectTimer; /// 最大重连次数 int maxReconnectTime = 5; StreamSubscription? streamSubscription; void connect({bool retry = false}) async { close(); try { var wsurl = url; if (backupUrl != null && backupUrl!.isNotEmpty && retry) { wsurl = backupUrl!; } webSocket = IOWebSocketChannel.connect( wsurl, connectTimeout: Duration(seconds: 10), headers: headers, ); await webSocket?.ready; ready(); } catch (e) { if (!retry) { connect(retry: true); return; } onError(e, e); } } /// 连接完成 void ready() { status = SocketStatus.connected; streamSubscription = webSocket?.stream.listen( (data) => receiveMessage(data), onError: (e, s) => onError(e, s), onDone: onDone, ); onReady?.call(); initHeartBeat(); } void initHeartBeat() { heartBeatTimer = Timer.periodic( Duration(milliseconds: heartBeatTime), (timer) { onHeartBeat?.call(); }, ); } void receiveMessage(dynamic data) { //接受到一条信息才算重连成功 reconnectTime = 0; onMessage?.call(data); } void onError(e, s) { status = SocketStatus.failed; onClose?.call(e.toString()); } void onDone() { if (status == SocketStatus.closed) { return; } onReconnect?.call(); reconnect(); } void sendMessage(dynamic message) { if (status == SocketStatus.connected) { webSocket?.sink.add(message); } } void close() { status = SocketStatus.closed; streamSubscription?.cancel(); reconnectTimer?.cancel(); reconnectTimer = null; webSocket?.sink.close(); heartBeatTimer?.cancel(); heartBeatTimer = null; } void reconnect() { status = SocketStatus.closed; if (reconnectTime < maxReconnectTime) { reconnectTime++; reconnectTimer ??= Timer.periodic(Duration(seconds: 5), (timer) { connect(); }); } else { onClose?.call("重连超过最大次数,与服务器断开连接"); reconnectTimer?.cancel(); reconnectTimer = null; close(); return; } } } ================================================ FILE: simple_live_core/lib/src/danmaku/bilibili_danmaku.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:brotli/brotli.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_core/src/common/convert_helper.dart'; import 'package:simple_live_core/src/common/web_socket_util.dart'; import '../common/binary_writer.dart'; class BiliBiliDanmakuArgs { final int roomId; final String token; final String buvid; final String serverHost; final int uid; final String cookie; BiliBiliDanmakuArgs({ required this.roomId, required this.token, required this.serverHost, required this.buvid, required this.uid, required this.cookie, }); @override String toString() { return json.encode({ "roomId": roomId, "token": token, "serverHost": serverHost, "buvid": buvid, "uid": uid, "cookie": cookie, }); } } class BiliBiliDanmaku implements LiveDanmaku { @override int heartbeatTime = 60 * 1000; @override Function(LiveMessage msg)? onMessage; @override Function(String msg)? onClose; @override Function()? onReady; //String serverUrl = "wss://broadcastlv.chat.bilibili.com/sub"; WebScoketUtils? webScoketUtils; late BiliBiliDanmakuArgs danmakuArgs; @override Future start(dynamic args) async { danmakuArgs = args as BiliBiliDanmakuArgs; webScoketUtils = WebScoketUtils( url: "wss://${args.serverHost}/sub", heartBeatTime: heartbeatTime, headers: args.cookie.isEmpty ? null : { "cookie": args.cookie, }, onMessage: (e) { decodeMessage(e); }, onReady: () { onReady?.call(); joinRoom(danmakuArgs); }, onHeartBeat: () { heartbeat(); }, onReconnect: () { onClose?.call("与服务器断开连接,正在尝试重连"); }, onClose: (e) { onClose?.call("服务器连接失败$e"); }, ); webScoketUtils?.connect(); } void joinRoom(BiliBiliDanmakuArgs args) { var joinData = encodeData( json.encode({ "uid": args.uid, "roomid": args.roomId, "protover": 3, "buvid": args.buvid, "platform": "web", "type": 2, "key": args.token, }), 7, ); webScoketUtils?.sendMessage(joinData); } @override void heartbeat() { webScoketUtils?.sendMessage(encodeData( "", 2, )); } @override Future stop() async { onMessage = null; onClose = null; webScoketUtils?.close(); } List encodeData(String msg, int action) { var data = utf8.encode(msg); //头部长度固定16 var length = data.length + 16; var buffer = Uint8List(length); var writer = BinaryWriter([]); //数据包长度 writer.writeInt(buffer.length, 4); //数据包头部长度,固定16 writer.writeInt(16, 2); //协议版本,0=JSON,1=Int32,2=Buffer writer.writeInt(0, 2); //操作类型 writer.writeInt(action, 4); //数据包头部长度,固定1 writer.writeInt(1, 4); writer.writeBytes(data); return writer.buffer; } void decodeMessage(List data) { try { //协议版本。0为JSON,可以直接解析;1为房间人气值,Body为4位Int32;2为压缩过Buffer,需要解压再处理 int protocolVersion = readInt(data, 6, 2); //操作类型。3=心跳回应,内容为房间人气值;5=通知,弹幕、广播等全部信息;8=进房回应,空 int operation = readInt(data, 8, 4); //内容 var body = data.skip(16).toList(); if (operation == 3) { var online = readInt(body, 0, 4); onMessage?.call( LiveMessage( type: LiveMessageType.online, data: online, color: LiveMessageColor.white, message: "", userName: "", ), ); } else if (operation == 5) { if (protocolVersion == 2) { body = zlib.decode(body); } else if (protocolVersion == 3) { body = brotli.decode(body); } var text = utf8.decode(body, allowMalformed: true); var group = text.split(RegExp(r"[\x00-\x1f]+", unicode: true, multiLine: true)); for (var item in group.where((x) => x.length > 2 && x.startsWith('{'))) { parseMessage(item); } } } catch (e) { CoreLog.error(e); } } void parseMessage(String jsonMessage) { try { var obj = json.decode(jsonMessage); var cmd = obj["cmd"].toString(); if (cmd.contains("DANMU_MSG")) { if (obj["info"] != null && obj["info"].length != 0) { var message = obj["info"][1].toString(); var color = asT(obj["info"][0][3]) ?? 0; if (obj["info"][2] != null && obj["info"][2].length != 0) { var username = obj["info"][2][1].toString(); var liveMsg = LiveMessage( type: LiveMessageType.chat, userName: username, message: message, color: color == 0 ? LiveMessageColor.white : LiveMessageColor.numberToColor(color), ); onMessage?.call(liveMsg); } } } else if (cmd == "SUPER_CHAT_MESSAGE") { if (obj["data"] == null) { return; } LiveSuperChatMessage sc = LiveSuperChatMessage( backgroundBottomColor: obj["data"]["background_bottom_color"].toString(), backgroundColor: obj["data"]["background_color"].toString(), endTime: DateTime.fromMillisecondsSinceEpoch( obj["data"]["end_time"] * 1000, ), face: "${obj["data"]["user_info"]["face"]}@200w.jpg", message: obj["data"]["message"].toString(), price: obj["data"]["price"], startTime: DateTime.fromMillisecondsSinceEpoch( obj["data"]["start_time"] * 1000, ), userName: obj["data"]["user_info"]["uname"].toString(), ); var liveMsg = LiveMessage( type: LiveMessageType.superChat, userName: "SUPER_CHAT_MESSAGE", message: "SUPER_CHAT_MESSAGE", color: LiveMessageColor.white, data: sc, ); onMessage?.call(liveMsg); } } catch (e) { CoreLog.error(e); } } int readInt(List buffer, int start, int len) { var bytes = Uint8List.fromList(buffer.getRange(start, start + len).toList()); var byteBuffer = bytes.buffer; var data = ByteData.view(byteBuffer); var result = 0; if (len == 1) { result = data.getUint8(0); } if (len == 2) { result = data.getInt16(0, Endian.big); } if (len == 4) { result = data.getInt32(0, Endian.big); } if (len == 8) { result = data.getInt64(0, Endian.big); } return result; } } ================================================ FILE: simple_live_core/lib/src/danmaku/douyin_danmaku.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_core/src/common/web_socket_util.dart'; import 'package:simple_live_core/src/scripts/douyin_sign.dart'; import 'proto/douyin.pb.dart'; class DouyinDanmakuArgs { final String webRid; final String roomId; final String userId; final String cookie; DouyinDanmakuArgs({ required this.webRid, required this.roomId, required this.userId, required this.cookie, }); @override String toString() { return json.encode({ "webRid": webRid, "roomId": roomId, "userId": userId, "cookie": cookie, }); } } class DouyinDanmaku implements LiveDanmaku { @override int heartbeatTime = 10 * 1000; @override Function(LiveMessage msg)? onMessage; @override Function(String msg)? onClose; @override Function()? onReady; String serverUrl = "wss://webcast3-ws-web-lq.douyin.com/webcast/im/push/v2/"; late DouyinDanmakuArgs danmakuArgs; WebScoketUtils? webScoketUtils; @override Future start(dynamic args) async { danmakuArgs = args as DouyinDanmakuArgs; var ts = DateTime.now().millisecondsSinceEpoch; var uri = Uri.parse(serverUrl).replace( scheme: "wss", queryParameters: { "app_name": "douyin_web", "version_code": "180800", "webcast_sdk_version": "1.3.0", "update_version_code": "1.3.0", "compress": "gzip", // "internal_ext": // "internal_src:dim|wss_push_room_id:${danmakuArgs.roomId}|wss_push_did:${danmakuArgs.userId}|dim_log_id:20230626152702E8F63662383A350588E1|fetch_time:1687764422114|seq:1|wss_info:0-1687764422114-0-0|wrds_kvs:WebcastRoomRankMessage-1687764036509597990_InputPanelComponentSyncData-1687736682345173033_WebcastRoomStatsMessage-1687764414427812578", "cursor": "h-1_t-${ts}_r-1_d-1_u-1", "host": "https://live.douyin.com", "aid": "6383", "live_id": "1", "did_rule": "3", "debug": "false", "maxCacheMessageNumber": "20", "endpoint": "live_pc", "support_wrds": "1", "im_path": "/webcast/im/fetch/", "user_unique_id": danmakuArgs.userId, "device_platform": "web", "cookie_enabled": "true", "screen_width": "1920", "screen_height": "1080", "browser_language": "zh-CN", "browser_platform": "Win32", "browser_name": "Mozilla", "browser_version": DouyinSite.kDefaultUserAgent.replaceAll( "Mozilla/", "", ), "browser_online": "true", "tz_name": "Asia/Shanghai", "identity": "audience", "room_id": danmakuArgs.roomId, "heartbeatDuration": "0", //"signature": "00000000" }, ); var sign = DouyinSign.getSignature(danmakuArgs.roomId, danmakuArgs.userId); var url = "$uri&signature=$sign"; var backupUrl = url.replaceAll("webcast3-ws-web-lq", "webcast5-ws-web-lf"); print(url); webScoketUtils = WebScoketUtils( url: url, backupUrl: backupUrl, headers: { "User-Agnet": DouyinSite.kDefaultUserAgent, "Cookie": danmakuArgs.cookie, "Origin": "https://live.douyin.com", }, heartBeatTime: heartbeatTime, onMessage: (e) { decodeMessage(e); }, onReady: () { onReady?.call(); joinRoom(args); }, onHeartBeat: () { heartbeat(); }, onReconnect: () { onClose?.call("与服务器断开连接,正在尝试重连"); }, onClose: (e) { onClose?.call("服务器连接失败$e"); }, ); webScoketUtils?.connect(); } @override void heartbeat() { var obj = PushFrame(); obj.payloadType = 'hb'; webScoketUtils?.sendMessage(obj.writeToBuffer()); } void decodeMessage(args) { // CoreLog.i(args.toString()); var wssPackage = PushFrame.fromBuffer(args); var logId = wssPackage.logId; var decompressed = gzip.decode(wssPackage.payload); var payloadPackage = Response.fromBuffer(decompressed); if (payloadPackage.needAck) { sendAck(logId, payloadPackage.internalExt); //return; } for (var msg in payloadPackage.messagesList) { if (msg.method == 'WebcastChatMessage') { unPackWebcastChatMessage(msg.payload); } else if (msg.method == 'WebcastRoomUserSeqMessage') { unPackWebcastRoomUserSeqMessage(msg.payload); } } } void unPackWebcastChatMessage(List payload) { var chatMessage = ChatMessage.fromBuffer(payload); onMessage?.call( LiveMessage( type: LiveMessageType.chat, color: LiveMessageColor.white, //暂不知道具体怎么转换颜色 // color: chatMessage.common.fullScreenTextColor. // ? LiveMessageColor.white // : LiveMessageColor.numberToColor(color), message: chatMessage.content, userName: chatMessage.user.nickName, ), ); } void unPackWebcastRoomUserSeqMessage(List payload) { var roomUserSeqMessage = RoomUserSeqMessage.fromBuffer(payload); onMessage?.call( LiveMessage( type: LiveMessageType.online, data: roomUserSeqMessage.totalUser.toInt(), color: LiveMessageColor.white, message: "", userName: "", ), ); } void sendAck(var logId, String internalExt) { var obj = PushFrame(); obj.payloadType = 'ack'; obj.logId = logId; obj.payloadType = internalExt; webScoketUtils?.sendMessage(obj.writeToBuffer()); } void joinRoom(args) { var obj = PushFrame(); obj.payloadType = 'hb'; webScoketUtils?.sendMessage(obj.writeToBuffer()); } @override Future stop() async { onMessage = null; onClose = null; webScoketUtils?.close(); } } ================================================ FILE: simple_live_core/lib/src/danmaku/douyu_danmaku.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_core/src/common/web_socket_util.dart'; import '../common/binary_writer.dart'; class DouyuDanmaku implements LiveDanmaku { @override int heartbeatTime = 45 * 1000; @override Function(LiveMessage msg)? onMessage; @override Function(String msg)? onClose; @override Function()? onReady; String serverUrl = "wss://danmuproxy.douyu.com:8506"; WebScoketUtils? webScoketUtils; @override Future start(dynamic args) async { webScoketUtils = WebScoketUtils( url: serverUrl, heartBeatTime: heartbeatTime, onMessage: (e) { decodeMessage(e); }, onReady: () { onReady?.call(); joinRoom(args); }, onHeartBeat: () { heartbeat(); }, onReconnect: () { onClose?.call("与服务器断开连接,正在尝试重连"); }, onClose: (e) { onClose?.call("服务器连接失败$e"); }, ); webScoketUtils?.connect(); } void joinRoom(roomId) { webScoketUtils ?.sendMessage(serializeDouyu("type@=loginreq/roomid@=$roomId/")); webScoketUtils?.sendMessage( serializeDouyu("type@=joingroup/rid@=$roomId/gid@=-9999/")); } @override void heartbeat() { var data = serializeDouyu("type@=mrkl/"); webScoketUtils?.sendMessage(data); } @override Future stop() async { onMessage = null; onClose = null; webScoketUtils?.close(); } void decodeMessage(List data) { try { String? result = deserializeDouyu(data); if (result == null) { return; } var jsonData = sttToJObject(result); var type = jsonData["type"]?.toString(); //斗鱼好像不会返回人气值 if (type == "chatmsg") { // 屏蔽阴间弹幕 if (jsonData["dms"] == null) { return; } var col = int.tryParse(jsonData["col"].toString()) ?? 0; var liveMsg = LiveMessage( type: LiveMessageType.chat, userName: jsonData["nn"].toString(), message: jsonData["txt"].toString(), color: getColor(col), ); onMessage?.call(liveMsg); } } catch (e) { CoreLog.error(e); } } List serializeDouyu(String body) { try { const int clientSendToServer = 689; const int encrypted = 0; const int reserved = 0; List buffer = utf8.encode(body); var writer = BinaryWriter([]); writer.writeInt(4 + 4 + body.length + 1, 4, endian: Endian.little); writer.writeInt(4 + 4 + body.length + 1, 4, endian: Endian.little); writer.writeInt(clientSendToServer, 2, endian: Endian.little); writer.writeInt(encrypted, 1, endian: Endian.little); writer.writeInt(reserved, 1, endian: Endian.little); writer.writeBytes(buffer); writer.writeInt(0, 1, endian: Endian.little); return writer.buffer; } catch (e) { CoreLog.error(e); return []; } } String? deserializeDouyu(List buffer) { try { var reader = BinaryReader(Uint8List.fromList(buffer)); int fullMsgLength = reader.readInt32(endian: Endian.little); //fullMsgLength reader.readInt32(endian: Endian.little); //fullMsgLength2 int bodyLength = fullMsgLength - 9; reader.readShort(endian: Endian.little); //packType reader.readByte(endian: Endian.little); //encrypted reader.readByte(endian: Endian.little); //reserved var bytes = reader.readBytes(bodyLength); reader.readByte(endian: Endian.little); //固定为0 return utf8.decode(bytes); } catch (e) { CoreLog.error(e); return null; } } //辣鸡STT dynamic sttToJObject(String str) { if (str.contains("//")) { var result = []; for (var field in str.split("//")) { if (field.isEmpty) { continue; } result.add(sttToJObject(field)); } return result; } if (str.contains("@=")) { var result = {}; for (var field in str.split('/')) { if (field.isEmpty) { continue; } var tokens = field.split("@="); var k = tokens[0]; var v = unscapeSlashAt(tokens[1]); result[k] = sttToJObject(v); } return result; } else if (str.contains("@A=")) { return sttToJObject(unscapeSlashAt(str)); } else { return unscapeSlashAt(str); } } String unscapeSlashAt(String str) { return str.replaceAll("@S", "/").replaceAll("@A", "@"); } LiveMessageColor getColor(int type) { switch (type) { case 1: return LiveMessageColor(255, 0, 0); case 2: return LiveMessageColor(30, 135, 240); case 3: return LiveMessageColor(122, 200, 75); case 4: return LiveMessageColor(255, 127, 0); case 5: return LiveMessageColor(155, 57, 244); case 6: return LiveMessageColor(255, 105, 180); default: return LiveMessageColor.white; } } } ================================================ FILE: simple_live_core/lib/src/danmaku/huya_danmaku.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_core/src/common/web_socket_util.dart'; import 'package:simple_live_core/src/model/tars/huya_danmaku.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; class HuyaDanmakuArgs { final int ayyuid; final int topSid; final int subSid; HuyaDanmakuArgs({ required this.ayyuid, required this.topSid, required this.subSid, }); @override String toString() { return json.encode({ "ayyuid": ayyuid, "topSid": topSid, "subSid": subSid, }); } } class HuyaDanmaku implements LiveDanmaku { @override int heartbeatTime = 60 * 1000; @override Function(LiveMessage msg)? onMessage; @override Function(String msg)? onClose; @override Function()? onReady; String serverUrl = "wss://cdnws.api.huya.com"; WebScoketUtils? webScoketUtils; final heartbeatData = base64.decode("ABQdAAwsNgBM"); late HuyaDanmakuArgs danmakuArgs; @override Future start(dynamic args) async { danmakuArgs = args as HuyaDanmakuArgs; webScoketUtils = WebScoketUtils( url: serverUrl, heartBeatTime: heartbeatTime, onMessage: (e) { decodeMessage(e); }, onReady: () { onReady?.call(); joinRoom(); }, onHeartBeat: () { heartbeat(); }, onReconnect: () { onClose?.call("与服务器断开连接,正在尝试重连"); }, onClose: (e) { onClose?.call("服务器连接失败$e"); }, ); webScoketUtils?.connect(); } void joinRoom() { var joinData = getJoinData(danmakuArgs.ayyuid, danmakuArgs.topSid, danmakuArgs.topSid); webScoketUtils?.sendMessage(joinData); } List getJoinData(int ayyuid, int tid, int sid) { try { var oos = TarsOutputStream(); oos.write(ayyuid, 0); oos.write(true, 1); oos.write("", 2); oos.write("", 3); oos.write(tid, 4); oos.write(sid, 5); oos.write(0, 6); oos.write(0, 7); var wscmd = TarsOutputStream(); wscmd.write(1, 0); wscmd.write(oos.toUint8List(), 1); return wscmd.toUint8List(); } catch (e) { CoreLog.error(e); return []; } } @override void heartbeat() { webScoketUtils?.sendMessage(heartbeatData); } @override Future stop() async { onMessage = null; onClose = null; webScoketUtils?.close(); } void decodeMessage(List data) { try { var stream = TarsInputStream(Uint8List.fromList(data)); var type = stream.read(0, 0, false); if (type == 7) { stream = TarsInputStream(stream.readBytes(1, false)); HYPushMessage wSPushMessage = HYPushMessage(); wSPushMessage.readFrom(stream); if (wSPushMessage.uri == 1400) { HYMessage messageNotice = HYMessage(); messageNotice .readFrom(TarsInputStream(Uint8List.fromList(wSPushMessage.msg))); var uname = messageNotice.userInfo.nickName; var content = messageNotice.content; var color = messageNotice.bulletFormat.fontColor; onMessage?.call( LiveMessage( type: LiveMessageType.chat, color: color <= 0 ? LiveMessageColor.white : LiveMessageColor.numberToColor(color), message: content, userName: uname, ), ); } else if (wSPushMessage.uri == 8006) { int online = 0; var s = TarsInputStream(Uint8List.fromList(wSPushMessage.msg)); online = s.read(online, 0, false); onMessage?.call( LiveMessage( type: LiveMessageType.online, data: online, color: LiveMessageColor.white, message: "", userName: "", ), ); } } } catch (e) { CoreLog.error(e); } } } ================================================ FILE: simple_live_core/lib/src/danmaku/proto/douyin.pb.dart ================================================ // // Generated code. Do not modify. // source: douyin.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides, camel_case_types // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import import 'dart:core' as $core; import 'package:fixnum/fixnum.dart' as $fixnum; import 'package:protobuf/protobuf.dart' as $pb; import 'douyin.pbenum.dart'; export 'douyin.pbenum.dart'; class Response extends $pb.GeneratedMessage { factory Response() => create(); Response._() : super(); factory Response.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Response.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Response', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..pc(1, _omitFieldNames ? '' : 'messagesList', $pb.PbFieldType.PM, protoName: 'messagesList', subBuilder: Message.create) ..aOS(2, _omitFieldNames ? '' : 'cursor') ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'fetchInterval', $pb.PbFieldType.OU6, protoName: 'fetchInterval', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'now', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(5, _omitFieldNames ? '' : 'internalExt', protoName: 'internalExt') ..a<$core.int>(6, _omitFieldNames ? '' : 'fetchType', $pb.PbFieldType.OU3, protoName: 'fetchType') ..m<$core.String, $core.String>(7, _omitFieldNames ? '' : 'routeParams', protoName: 'routeParams', entryClassName: 'Response.RouteParamsEntry', keyFieldType: $pb.PbFieldType.OS, valueFieldType: $pb.PbFieldType.OS, packageName: const $pb.PackageName('douyin')) ..a<$fixnum.Int64>(8, _omitFieldNames ? '' : 'heartbeatDuration', $pb.PbFieldType.OU6, protoName: 'heartbeatDuration', defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(9, _omitFieldNames ? '' : 'needAck', protoName: 'needAck') ..aOS(10, _omitFieldNames ? '' : 'pushServer', protoName: 'pushServer') ..aOS(11, _omitFieldNames ? '' : 'liveCursor', protoName: 'liveCursor') ..aOB(12, _omitFieldNames ? '' : 'historyNoMore', protoName: 'historyNoMore') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Response clone() => Response()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Response copyWith(void Function(Response) updates) => super.copyWith((message) => updates(message as Response)) as Response; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Response create() => Response._(); Response createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Response getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Response? _defaultInstance; @$pb.TagNumber(1) $core.List get messagesList => $_getList(0); @$pb.TagNumber(2) $core.String get cursor => $_getSZ(1); @$pb.TagNumber(2) set cursor($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasCursor() => $_has(1); @$pb.TagNumber(2) void clearCursor() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get fetchInterval => $_getI64(2); @$pb.TagNumber(3) set fetchInterval($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasFetchInterval() => $_has(2); @$pb.TagNumber(3) void clearFetchInterval() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get now => $_getI64(3); @$pb.TagNumber(4) set now($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasNow() => $_has(3); @$pb.TagNumber(4) void clearNow() => clearField(4); @$pb.TagNumber(5) $core.String get internalExt => $_getSZ(4); @$pb.TagNumber(5) set internalExt($core.String v) { $_setString(4, v); } @$pb.TagNumber(5) $core.bool hasInternalExt() => $_has(4); @$pb.TagNumber(5) void clearInternalExt() => clearField(5); @$pb.TagNumber(6) $core.int get fetchType => $_getIZ(5); @$pb.TagNumber(6) set fetchType($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasFetchType() => $_has(5); @$pb.TagNumber(6) void clearFetchType() => clearField(6); @$pb.TagNumber(7) $core.Map<$core.String, $core.String> get routeParams => $_getMap(6); @$pb.TagNumber(8) $fixnum.Int64 get heartbeatDuration => $_getI64(7); @$pb.TagNumber(8) set heartbeatDuration($fixnum.Int64 v) { $_setInt64(7, v); } @$pb.TagNumber(8) $core.bool hasHeartbeatDuration() => $_has(7); @$pb.TagNumber(8) void clearHeartbeatDuration() => clearField(8); @$pb.TagNumber(9) $core.bool get needAck => $_getBF(8); @$pb.TagNumber(9) set needAck($core.bool v) { $_setBool(8, v); } @$pb.TagNumber(9) $core.bool hasNeedAck() => $_has(8); @$pb.TagNumber(9) void clearNeedAck() => clearField(9); @$pb.TagNumber(10) $core.String get pushServer => $_getSZ(9); @$pb.TagNumber(10) set pushServer($core.String v) { $_setString(9, v); } @$pb.TagNumber(10) $core.bool hasPushServer() => $_has(9); @$pb.TagNumber(10) void clearPushServer() => clearField(10); @$pb.TagNumber(11) $core.String get liveCursor => $_getSZ(10); @$pb.TagNumber(11) set liveCursor($core.String v) { $_setString(10, v); } @$pb.TagNumber(11) $core.bool hasLiveCursor() => $_has(10); @$pb.TagNumber(11) void clearLiveCursor() => clearField(11); @$pb.TagNumber(12) $core.bool get historyNoMore => $_getBF(11); @$pb.TagNumber(12) set historyNoMore($core.bool v) { $_setBool(11, v); } @$pb.TagNumber(12) $core.bool hasHistoryNoMore() => $_has(11); @$pb.TagNumber(12) void clearHistoryNoMore() => clearField(12); } class Message extends $pb.GeneratedMessage { factory Message() => create(); Message._() : super(); factory Message.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Message.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Message', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'method') ..a<$core.List<$core.int>>(2, _omitFieldNames ? '' : 'payload', $pb.PbFieldType.OY) ..aInt64(3, _omitFieldNames ? '' : 'msgId', protoName: 'msgId') ..a<$core.int>(4, _omitFieldNames ? '' : 'msgType', $pb.PbFieldType.O3, protoName: 'msgType') ..aInt64(5, _omitFieldNames ? '' : 'offset') ..aOB(6, _omitFieldNames ? '' : 'needWrdsStore', protoName: 'needWrdsStore') ..aInt64(7, _omitFieldNames ? '' : 'wrdsVersion', protoName: 'wrdsVersion') ..aOS(8, _omitFieldNames ? '' : 'wrdsSubKey', protoName: 'wrdsSubKey') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Message clone() => Message()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Message copyWith(void Function(Message) updates) => super.copyWith((message) => updates(message as Message)) as Message; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Message create() => Message._(); Message createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Message getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Message? _defaultInstance; @$pb.TagNumber(1) $core.String get method => $_getSZ(0); @$pb.TagNumber(1) set method($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasMethod() => $_has(0); @$pb.TagNumber(1) void clearMethod() => clearField(1); @$pb.TagNumber(2) $core.List<$core.int> get payload => $_getN(1); @$pb.TagNumber(2) set payload($core.List<$core.int> v) { $_setBytes(1, v); } @$pb.TagNumber(2) $core.bool hasPayload() => $_has(1); @$pb.TagNumber(2) void clearPayload() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get msgId => $_getI64(2); @$pb.TagNumber(3) set msgId($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasMsgId() => $_has(2); @$pb.TagNumber(3) void clearMsgId() => clearField(3); @$pb.TagNumber(4) $core.int get msgType => $_getIZ(3); @$pb.TagNumber(4) set msgType($core.int v) { $_setSignedInt32(3, v); } @$pb.TagNumber(4) $core.bool hasMsgType() => $_has(3); @$pb.TagNumber(4) void clearMsgType() => clearField(4); @$pb.TagNumber(5) $fixnum.Int64 get offset => $_getI64(4); @$pb.TagNumber(5) set offset($fixnum.Int64 v) { $_setInt64(4, v); } @$pb.TagNumber(5) $core.bool hasOffset() => $_has(4); @$pb.TagNumber(5) void clearOffset() => clearField(5); @$pb.TagNumber(6) $core.bool get needWrdsStore => $_getBF(5); @$pb.TagNumber(6) set needWrdsStore($core.bool v) { $_setBool(5, v); } @$pb.TagNumber(6) $core.bool hasNeedWrdsStore() => $_has(5); @$pb.TagNumber(6) void clearNeedWrdsStore() => clearField(6); @$pb.TagNumber(7) $fixnum.Int64 get wrdsVersion => $_getI64(6); @$pb.TagNumber(7) set wrdsVersion($fixnum.Int64 v) { $_setInt64(6, v); } @$pb.TagNumber(7) $core.bool hasWrdsVersion() => $_has(6); @$pb.TagNumber(7) void clearWrdsVersion() => clearField(7); @$pb.TagNumber(8) $core.String get wrdsSubKey => $_getSZ(7); @$pb.TagNumber(8) set wrdsSubKey($core.String v) { $_setString(7, v); } @$pb.TagNumber(8) $core.bool hasWrdsSubKey() => $_has(7); @$pb.TagNumber(8) void clearWrdsSubKey() => clearField(8); } class ChatMessage extends $pb.GeneratedMessage { factory ChatMessage() => create(); ChatMessage._() : super(); factory ChatMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory ChatMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ChatMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..aOM(2, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..aOS(3, _omitFieldNames ? '' : 'content') ..aOB(4, _omitFieldNames ? '' : 'visibleToSender', protoName: 'visibleToSender') ..aOM(5, _omitFieldNames ? '' : 'backgroundImage', protoName: 'backgroundImage', subBuilder: Image.create) ..aOS(6, _omitFieldNames ? '' : 'fullScreenTextColor', protoName: 'fullScreenTextColor') ..aOM(7, _omitFieldNames ? '' : 'backgroundImageV2', protoName: 'backgroundImageV2', subBuilder: Image.create) ..aOM(8, _omitFieldNames ? '' : 'publicAreaCommon', protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create) ..aOM(9, _omitFieldNames ? '' : 'giftImage', protoName: 'giftImage', subBuilder: Image.create) ..a<$fixnum.Int64>(11, _omitFieldNames ? '' : 'agreeMsgId', $pb.PbFieldType.OU6, protoName: 'agreeMsgId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$core.int>(12, _omitFieldNames ? '' : 'priorityLevel', $pb.PbFieldType.OU3, protoName: 'priorityLevel') ..aOM(13, _omitFieldNames ? '' : 'landscapeAreaCommon', protoName: 'landscapeAreaCommon', subBuilder: LandscapeAreaCommon.create) ..a<$fixnum.Int64>(15, _omitFieldNames ? '' : 'eventTime', $pb.PbFieldType.OU6, protoName: 'eventTime', defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(16, _omitFieldNames ? '' : 'sendReview', protoName: 'sendReview') ..aOB(17, _omitFieldNames ? '' : 'fromIntercom', protoName: 'fromIntercom') ..aOB(18, _omitFieldNames ? '' : 'intercomHideUserCard', protoName: 'intercomHideUserCard') ..aOS(20, _omitFieldNames ? '' : 'chatBy', protoName: 'chatBy') ..a<$core.int>(21, _omitFieldNames ? '' : 'individualChatPriority', $pb.PbFieldType.OU3, protoName: 'individualChatPriority') ..aOM(22, _omitFieldNames ? '' : 'rtfContent', protoName: 'rtfContent', subBuilder: Text.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') ChatMessage clone() => ChatMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') ChatMessage copyWith(void Function(ChatMessage) updates) => super.copyWith((message) => updates(message as ChatMessage)) as ChatMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ChatMessage create() => ChatMessage._(); ChatMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static ChatMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static ChatMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) User get user => $_getN(1); @$pb.TagNumber(2) set user(User v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasUser() => $_has(1); @$pb.TagNumber(2) void clearUser() => clearField(2); @$pb.TagNumber(2) User ensureUser() => $_ensure(1); @$pb.TagNumber(3) $core.String get content => $_getSZ(2); @$pb.TagNumber(3) set content($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasContent() => $_has(2); @$pb.TagNumber(3) void clearContent() => clearField(3); @$pb.TagNumber(4) $core.bool get visibleToSender => $_getBF(3); @$pb.TagNumber(4) set visibleToSender($core.bool v) { $_setBool(3, v); } @$pb.TagNumber(4) $core.bool hasVisibleToSender() => $_has(3); @$pb.TagNumber(4) void clearVisibleToSender() => clearField(4); @$pb.TagNumber(5) Image get backgroundImage => $_getN(4); @$pb.TagNumber(5) set backgroundImage(Image v) { setField(5, v); } @$pb.TagNumber(5) $core.bool hasBackgroundImage() => $_has(4); @$pb.TagNumber(5) void clearBackgroundImage() => clearField(5); @$pb.TagNumber(5) Image ensureBackgroundImage() => $_ensure(4); @$pb.TagNumber(6) $core.String get fullScreenTextColor => $_getSZ(5); @$pb.TagNumber(6) set fullScreenTextColor($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) $core.bool hasFullScreenTextColor() => $_has(5); @$pb.TagNumber(6) void clearFullScreenTextColor() => clearField(6); @$pb.TagNumber(7) Image get backgroundImageV2 => $_getN(6); @$pb.TagNumber(7) set backgroundImageV2(Image v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasBackgroundImageV2() => $_has(6); @$pb.TagNumber(7) void clearBackgroundImageV2() => clearField(7); @$pb.TagNumber(7) Image ensureBackgroundImageV2() => $_ensure(6); @$pb.TagNumber(8) PublicAreaCommon get publicAreaCommon => $_getN(7); @$pb.TagNumber(8) set publicAreaCommon(PublicAreaCommon v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasPublicAreaCommon() => $_has(7); @$pb.TagNumber(8) void clearPublicAreaCommon() => clearField(8); @$pb.TagNumber(8) PublicAreaCommon ensurePublicAreaCommon() => $_ensure(7); @$pb.TagNumber(9) Image get giftImage => $_getN(8); @$pb.TagNumber(9) set giftImage(Image v) { setField(9, v); } @$pb.TagNumber(9) $core.bool hasGiftImage() => $_has(8); @$pb.TagNumber(9) void clearGiftImage() => clearField(9); @$pb.TagNumber(9) Image ensureGiftImage() => $_ensure(8); @$pb.TagNumber(11) $fixnum.Int64 get agreeMsgId => $_getI64(9); @$pb.TagNumber(11) set agreeMsgId($fixnum.Int64 v) { $_setInt64(9, v); } @$pb.TagNumber(11) $core.bool hasAgreeMsgId() => $_has(9); @$pb.TagNumber(11) void clearAgreeMsgId() => clearField(11); @$pb.TagNumber(12) $core.int get priorityLevel => $_getIZ(10); @$pb.TagNumber(12) set priorityLevel($core.int v) { $_setUnsignedInt32(10, v); } @$pb.TagNumber(12) $core.bool hasPriorityLevel() => $_has(10); @$pb.TagNumber(12) void clearPriorityLevel() => clearField(12); @$pb.TagNumber(13) LandscapeAreaCommon get landscapeAreaCommon => $_getN(11); @$pb.TagNumber(13) set landscapeAreaCommon(LandscapeAreaCommon v) { setField(13, v); } @$pb.TagNumber(13) $core.bool hasLandscapeAreaCommon() => $_has(11); @$pb.TagNumber(13) void clearLandscapeAreaCommon() => clearField(13); @$pb.TagNumber(13) LandscapeAreaCommon ensureLandscapeAreaCommon() => $_ensure(11); @$pb.TagNumber(15) $fixnum.Int64 get eventTime => $_getI64(12); @$pb.TagNumber(15) set eventTime($fixnum.Int64 v) { $_setInt64(12, v); } @$pb.TagNumber(15) $core.bool hasEventTime() => $_has(12); @$pb.TagNumber(15) void clearEventTime() => clearField(15); @$pb.TagNumber(16) $core.bool get sendReview => $_getBF(13); @$pb.TagNumber(16) set sendReview($core.bool v) { $_setBool(13, v); } @$pb.TagNumber(16) $core.bool hasSendReview() => $_has(13); @$pb.TagNumber(16) void clearSendReview() => clearField(16); @$pb.TagNumber(17) $core.bool get fromIntercom => $_getBF(14); @$pb.TagNumber(17) set fromIntercom($core.bool v) { $_setBool(14, v); } @$pb.TagNumber(17) $core.bool hasFromIntercom() => $_has(14); @$pb.TagNumber(17) void clearFromIntercom() => clearField(17); @$pb.TagNumber(18) $core.bool get intercomHideUserCard => $_getBF(15); @$pb.TagNumber(18) set intercomHideUserCard($core.bool v) { $_setBool(15, v); } @$pb.TagNumber(18) $core.bool hasIntercomHideUserCard() => $_has(15); @$pb.TagNumber(18) void clearIntercomHideUserCard() => clearField(18); @$pb.TagNumber(20) $core.String get chatBy => $_getSZ(16); @$pb.TagNumber(20) set chatBy($core.String v) { $_setString(16, v); } @$pb.TagNumber(20) $core.bool hasChatBy() => $_has(16); @$pb.TagNumber(20) void clearChatBy() => clearField(20); @$pb.TagNumber(21) $core.int get individualChatPriority => $_getIZ(17); @$pb.TagNumber(21) set individualChatPriority($core.int v) { $_setUnsignedInt32(17, v); } @$pb.TagNumber(21) $core.bool hasIndividualChatPriority() => $_has(17); @$pb.TagNumber(21) void clearIndividualChatPriority() => clearField(21); @$pb.TagNumber(22) Text get rtfContent => $_getN(18); @$pb.TagNumber(22) set rtfContent(Text v) { setField(22, v); } @$pb.TagNumber(22) $core.bool hasRtfContent() => $_has(18); @$pb.TagNumber(22) void clearRtfContent() => clearField(22); @$pb.TagNumber(22) Text ensureRtfContent() => $_ensure(18); } class LandscapeAreaCommon extends $pb.GeneratedMessage { factory LandscapeAreaCommon() => create(); LandscapeAreaCommon._() : super(); factory LandscapeAreaCommon.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory LandscapeAreaCommon.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'LandscapeAreaCommon', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOB(1, _omitFieldNames ? '' : 'showHead', protoName: 'showHead') ..aOB(2, _omitFieldNames ? '' : 'showNickname', protoName: 'showNickname') ..aOB(3, _omitFieldNames ? '' : 'showFontColor', protoName: 'showFontColor') ..pPS(4, _omitFieldNames ? '' : 'colorValueList', protoName: 'colorValueList') ..pc(5, _omitFieldNames ? '' : 'commentTypeTagsList', $pb.PbFieldType.KE, protoName: 'commentTypeTagsList', valueOf: CommentTypeTag.valueOf, enumValues: CommentTypeTag.values, defaultEnumValue: CommentTypeTag.COMMENTTYPETAGUNKNOWN) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') LandscapeAreaCommon clone() => LandscapeAreaCommon()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') LandscapeAreaCommon copyWith(void Function(LandscapeAreaCommon) updates) => super.copyWith((message) => updates(message as LandscapeAreaCommon)) as LandscapeAreaCommon; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static LandscapeAreaCommon create() => LandscapeAreaCommon._(); LandscapeAreaCommon createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static LandscapeAreaCommon getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static LandscapeAreaCommon? _defaultInstance; @$pb.TagNumber(1) $core.bool get showHead => $_getBF(0); @$pb.TagNumber(1) set showHead($core.bool v) { $_setBool(0, v); } @$pb.TagNumber(1) $core.bool hasShowHead() => $_has(0); @$pb.TagNumber(1) void clearShowHead() => clearField(1); @$pb.TagNumber(2) $core.bool get showNickname => $_getBF(1); @$pb.TagNumber(2) set showNickname($core.bool v) { $_setBool(1, v); } @$pb.TagNumber(2) $core.bool hasShowNickname() => $_has(1); @$pb.TagNumber(2) void clearShowNickname() => clearField(2); @$pb.TagNumber(3) $core.bool get showFontColor => $_getBF(2); @$pb.TagNumber(3) set showFontColor($core.bool v) { $_setBool(2, v); } @$pb.TagNumber(3) $core.bool hasShowFontColor() => $_has(2); @$pb.TagNumber(3) void clearShowFontColor() => clearField(3); @$pb.TagNumber(4) $core.List<$core.String> get colorValueList => $_getList(3); @$pb.TagNumber(5) $core.List get commentTypeTagsList => $_getList(4); } class RoomUserSeqMessage extends $pb.GeneratedMessage { factory RoomUserSeqMessage() => create(); RoomUserSeqMessage._() : super(); factory RoomUserSeqMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory RoomUserSeqMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RoomUserSeqMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..pc(2, _omitFieldNames ? '' : 'ranksList', $pb.PbFieldType.PM, protoName: 'ranksList', subBuilder: RoomUserSeqMessageContributor.create) ..aInt64(3, _omitFieldNames ? '' : 'total') ..aOS(4, _omitFieldNames ? '' : 'popStr', protoName: 'popStr') ..pc(5, _omitFieldNames ? '' : 'seatsList', $pb.PbFieldType.PM, protoName: 'seatsList', subBuilder: RoomUserSeqMessageContributor.create) ..aInt64(6, _omitFieldNames ? '' : 'popularity') ..aInt64(7, _omitFieldNames ? '' : 'totalUser', protoName: 'totalUser') ..aOS(8, _omitFieldNames ? '' : 'totalUserStr', protoName: 'totalUserStr') ..aOS(9, _omitFieldNames ? '' : 'totalStr', protoName: 'totalStr') ..aOS(10, _omitFieldNames ? '' : 'onlineUserForAnchor', protoName: 'onlineUserForAnchor') ..aOS(11, _omitFieldNames ? '' : 'totalPvForAnchor', protoName: 'totalPvForAnchor') ..aOS(12, _omitFieldNames ? '' : 'upRightStatsStr', protoName: 'upRightStatsStr') ..aOS(13, _omitFieldNames ? '' : 'upRightStatsStrComplete', protoName: 'upRightStatsStrComplete') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') RoomUserSeqMessage clone() => RoomUserSeqMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') RoomUserSeqMessage copyWith(void Function(RoomUserSeqMessage) updates) => super.copyWith((message) => updates(message as RoomUserSeqMessage)) as RoomUserSeqMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static RoomUserSeqMessage create() => RoomUserSeqMessage._(); RoomUserSeqMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static RoomUserSeqMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static RoomUserSeqMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) $core.List get ranksList => $_getList(1); @$pb.TagNumber(3) $fixnum.Int64 get total => $_getI64(2); @$pb.TagNumber(3) set total($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasTotal() => $_has(2); @$pb.TagNumber(3) void clearTotal() => clearField(3); @$pb.TagNumber(4) $core.String get popStr => $_getSZ(3); @$pb.TagNumber(4) set popStr($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasPopStr() => $_has(3); @$pb.TagNumber(4) void clearPopStr() => clearField(4); @$pb.TagNumber(5) $core.List get seatsList => $_getList(4); @$pb.TagNumber(6) $fixnum.Int64 get popularity => $_getI64(5); @$pb.TagNumber(6) set popularity($fixnum.Int64 v) { $_setInt64(5, v); } @$pb.TagNumber(6) $core.bool hasPopularity() => $_has(5); @$pb.TagNumber(6) void clearPopularity() => clearField(6); @$pb.TagNumber(7) $fixnum.Int64 get totalUser => $_getI64(6); @$pb.TagNumber(7) set totalUser($fixnum.Int64 v) { $_setInt64(6, v); } @$pb.TagNumber(7) $core.bool hasTotalUser() => $_has(6); @$pb.TagNumber(7) void clearTotalUser() => clearField(7); @$pb.TagNumber(8) $core.String get totalUserStr => $_getSZ(7); @$pb.TagNumber(8) set totalUserStr($core.String v) { $_setString(7, v); } @$pb.TagNumber(8) $core.bool hasTotalUserStr() => $_has(7); @$pb.TagNumber(8) void clearTotalUserStr() => clearField(8); @$pb.TagNumber(9) $core.String get totalStr => $_getSZ(8); @$pb.TagNumber(9) set totalStr($core.String v) { $_setString(8, v); } @$pb.TagNumber(9) $core.bool hasTotalStr() => $_has(8); @$pb.TagNumber(9) void clearTotalStr() => clearField(9); @$pb.TagNumber(10) $core.String get onlineUserForAnchor => $_getSZ(9); @$pb.TagNumber(10) set onlineUserForAnchor($core.String v) { $_setString(9, v); } @$pb.TagNumber(10) $core.bool hasOnlineUserForAnchor() => $_has(9); @$pb.TagNumber(10) void clearOnlineUserForAnchor() => clearField(10); @$pb.TagNumber(11) $core.String get totalPvForAnchor => $_getSZ(10); @$pb.TagNumber(11) set totalPvForAnchor($core.String v) { $_setString(10, v); } @$pb.TagNumber(11) $core.bool hasTotalPvForAnchor() => $_has(10); @$pb.TagNumber(11) void clearTotalPvForAnchor() => clearField(11); @$pb.TagNumber(12) $core.String get upRightStatsStr => $_getSZ(11); @$pb.TagNumber(12) set upRightStatsStr($core.String v) { $_setString(11, v); } @$pb.TagNumber(12) $core.bool hasUpRightStatsStr() => $_has(11); @$pb.TagNumber(12) void clearUpRightStatsStr() => clearField(12); @$pb.TagNumber(13) $core.String get upRightStatsStrComplete => $_getSZ(12); @$pb.TagNumber(13) set upRightStatsStrComplete($core.String v) { $_setString(12, v); } @$pb.TagNumber(13) $core.bool hasUpRightStatsStrComplete() => $_has(12); @$pb.TagNumber(13) void clearUpRightStatsStrComplete() => clearField(13); } class CommonTextMessage extends $pb.GeneratedMessage { factory CommonTextMessage() => create(); CommonTextMessage._() : super(); factory CommonTextMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory CommonTextMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CommonTextMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..aOM(2, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..aOS(3, _omitFieldNames ? '' : 'scene') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') CommonTextMessage clone() => CommonTextMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') CommonTextMessage copyWith(void Function(CommonTextMessage) updates) => super.copyWith((message) => updates(message as CommonTextMessage)) as CommonTextMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static CommonTextMessage create() => CommonTextMessage._(); CommonTextMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static CommonTextMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static CommonTextMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) User get user => $_getN(1); @$pb.TagNumber(2) set user(User v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasUser() => $_has(1); @$pb.TagNumber(2) void clearUser() => clearField(2); @$pb.TagNumber(2) User ensureUser() => $_ensure(1); @$pb.TagNumber(3) $core.String get scene => $_getSZ(2); @$pb.TagNumber(3) set scene($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasScene() => $_has(2); @$pb.TagNumber(3) void clearScene() => clearField(3); } class UpdateFanTicketMessage extends $pb.GeneratedMessage { factory UpdateFanTicketMessage() => create(); UpdateFanTicketMessage._() : super(); factory UpdateFanTicketMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory UpdateFanTicketMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateFanTicketMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..aOS(2, _omitFieldNames ? '' : 'roomFanTicketCountText', protoName: 'roomFanTicketCountText') ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'roomFanTicketCount', $pb.PbFieldType.OU6, protoName: 'roomFanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(4, _omitFieldNames ? '' : 'forceUpdate', protoName: 'forceUpdate') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') UpdateFanTicketMessage clone() => UpdateFanTicketMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') UpdateFanTicketMessage copyWith(void Function(UpdateFanTicketMessage) updates) => super.copyWith((message) => updates(message as UpdateFanTicketMessage)) as UpdateFanTicketMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static UpdateFanTicketMessage create() => UpdateFanTicketMessage._(); UpdateFanTicketMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static UpdateFanTicketMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static UpdateFanTicketMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) $core.String get roomFanTicketCountText => $_getSZ(1); @$pb.TagNumber(2) set roomFanTicketCountText($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasRoomFanTicketCountText() => $_has(1); @$pb.TagNumber(2) void clearRoomFanTicketCountText() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get roomFanTicketCount => $_getI64(2); @$pb.TagNumber(3) set roomFanTicketCount($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasRoomFanTicketCount() => $_has(2); @$pb.TagNumber(3) void clearRoomFanTicketCount() => clearField(3); @$pb.TagNumber(4) $core.bool get forceUpdate => $_getBF(3); @$pb.TagNumber(4) set forceUpdate($core.bool v) { $_setBool(3, v); } @$pb.TagNumber(4) $core.bool hasForceUpdate() => $_has(3); @$pb.TagNumber(4) void clearForceUpdate() => clearField(4); } class RoomUserSeqMessageContributor extends $pb.GeneratedMessage { factory RoomUserSeqMessageContributor() => create(); RoomUserSeqMessageContributor._() : super(); factory RoomUserSeqMessageContributor.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory RoomUserSeqMessageContributor.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RoomUserSeqMessageContributor', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'score', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(2, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'rank', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'delta', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(5, _omitFieldNames ? '' : 'isHidden', protoName: 'isHidden') ..aOS(6, _omitFieldNames ? '' : 'scoreDescription', protoName: 'scoreDescription') ..aOS(7, _omitFieldNames ? '' : 'exactlyScore', protoName: 'exactlyScore') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') RoomUserSeqMessageContributor clone() => RoomUserSeqMessageContributor()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') RoomUserSeqMessageContributor copyWith(void Function(RoomUserSeqMessageContributor) updates) => super.copyWith((message) => updates(message as RoomUserSeqMessageContributor)) as RoomUserSeqMessageContributor; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static RoomUserSeqMessageContributor create() => RoomUserSeqMessageContributor._(); RoomUserSeqMessageContributor createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static RoomUserSeqMessageContributor getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static RoomUserSeqMessageContributor? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get score => $_getI64(0); @$pb.TagNumber(1) set score($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasScore() => $_has(0); @$pb.TagNumber(1) void clearScore() => clearField(1); @$pb.TagNumber(2) User get user => $_getN(1); @$pb.TagNumber(2) set user(User v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasUser() => $_has(1); @$pb.TagNumber(2) void clearUser() => clearField(2); @$pb.TagNumber(2) User ensureUser() => $_ensure(1); @$pb.TagNumber(3) $fixnum.Int64 get rank => $_getI64(2); @$pb.TagNumber(3) set rank($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasRank() => $_has(2); @$pb.TagNumber(3) void clearRank() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get delta => $_getI64(3); @$pb.TagNumber(4) set delta($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasDelta() => $_has(3); @$pb.TagNumber(4) void clearDelta() => clearField(4); @$pb.TagNumber(5) $core.bool get isHidden => $_getBF(4); @$pb.TagNumber(5) set isHidden($core.bool v) { $_setBool(4, v); } @$pb.TagNumber(5) $core.bool hasIsHidden() => $_has(4); @$pb.TagNumber(5) void clearIsHidden() => clearField(5); @$pb.TagNumber(6) $core.String get scoreDescription => $_getSZ(5); @$pb.TagNumber(6) set scoreDescription($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) $core.bool hasScoreDescription() => $_has(5); @$pb.TagNumber(6) void clearScoreDescription() => clearField(6); @$pb.TagNumber(7) $core.String get exactlyScore => $_getSZ(6); @$pb.TagNumber(7) set exactlyScore($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasExactlyScore() => $_has(6); @$pb.TagNumber(7) void clearExactlyScore() => clearField(7); } class GiftMessage extends $pb.GeneratedMessage { factory GiftMessage() => create(); GiftMessage._() : super(); factory GiftMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory GiftMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GiftMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'giftId', $pb.PbFieldType.OU6, protoName: 'giftId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'fanTicketCount', $pb.PbFieldType.OU6, protoName: 'fanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'groupCount', $pb.PbFieldType.OU6, protoName: 'groupCount', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'repeatCount', $pb.PbFieldType.OU6, protoName: 'repeatCount', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(6, _omitFieldNames ? '' : 'comboCount', $pb.PbFieldType.OU6, protoName: 'comboCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(7, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..aOM(8, _omitFieldNames ? '' : 'toUser', protoName: 'toUser', subBuilder: User.create) ..a<$core.int>(9, _omitFieldNames ? '' : 'repeatEnd', $pb.PbFieldType.OU3, protoName: 'repeatEnd') ..aOM(10, _omitFieldNames ? '' : 'textEffect', protoName: 'textEffect', subBuilder: TextEffect.create) ..a<$fixnum.Int64>(11, _omitFieldNames ? '' : 'groupId', $pb.PbFieldType.OU6, protoName: 'groupId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(12, _omitFieldNames ? '' : 'incomeTaskgifts', $pb.PbFieldType.OU6, protoName: 'incomeTaskgifts', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(13, _omitFieldNames ? '' : 'roomFanTicketCount', $pb.PbFieldType.OU6, protoName: 'roomFanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(14, _omitFieldNames ? '' : 'priority', subBuilder: GiftIMPriority.create) ..aOM(15, _omitFieldNames ? '' : 'gift', subBuilder: GiftStruct.create) ..aOS(16, _omitFieldNames ? '' : 'logId', protoName: 'logId') ..a<$fixnum.Int64>(17, _omitFieldNames ? '' : 'sendType', $pb.PbFieldType.OU6, protoName: 'sendType', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(18, _omitFieldNames ? '' : 'publicAreaCommon', protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create) ..aOM(19, _omitFieldNames ? '' : 'trayDisplayText', protoName: 'trayDisplayText', subBuilder: Text.create) ..a<$fixnum.Int64>(20, _omitFieldNames ? '' : 'bannedDisplayEffects', $pb.PbFieldType.OU6, protoName: 'bannedDisplayEffects', defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(25, _omitFieldNames ? '' : 'displayForSelf', protoName: 'displayForSelf') ..aOS(26, _omitFieldNames ? '' : 'interactGiftInfo', protoName: 'interactGiftInfo') ..aOS(27, _omitFieldNames ? '' : 'diyItemInfo', protoName: 'diyItemInfo') ..p<$fixnum.Int64>(28, _omitFieldNames ? '' : 'minAssetSetList', $pb.PbFieldType.KU6, protoName: 'minAssetSetList') ..a<$fixnum.Int64>(29, _omitFieldNames ? '' : 'totalCount', $pb.PbFieldType.OU6, protoName: 'totalCount', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$core.int>(30, _omitFieldNames ? '' : 'clientGiftSource', $pb.PbFieldType.OU3, protoName: 'clientGiftSource') ..p<$fixnum.Int64>(32, _omitFieldNames ? '' : 'toUserIdsList', $pb.PbFieldType.KU6, protoName: 'toUserIdsList') ..a<$fixnum.Int64>(33, _omitFieldNames ? '' : 'sendTime', $pb.PbFieldType.OU6, protoName: 'sendTime', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(34, _omitFieldNames ? '' : 'forceDisplayEffects', $pb.PbFieldType.OU6, protoName: 'forceDisplayEffects', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(35, _omitFieldNames ? '' : 'traceId', protoName: 'traceId') ..a<$fixnum.Int64>(36, _omitFieldNames ? '' : 'effectDisplayTs', $pb.PbFieldType.OU6, protoName: 'effectDisplayTs', defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') GiftMessage clone() => GiftMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') GiftMessage copyWith(void Function(GiftMessage) updates) => super.copyWith((message) => updates(message as GiftMessage)) as GiftMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static GiftMessage create() => GiftMessage._(); GiftMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static GiftMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static GiftMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) $fixnum.Int64 get giftId => $_getI64(1); @$pb.TagNumber(2) set giftId($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasGiftId() => $_has(1); @$pb.TagNumber(2) void clearGiftId() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get fanTicketCount => $_getI64(2); @$pb.TagNumber(3) set fanTicketCount($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasFanTicketCount() => $_has(2); @$pb.TagNumber(3) void clearFanTicketCount() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get groupCount => $_getI64(3); @$pb.TagNumber(4) set groupCount($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasGroupCount() => $_has(3); @$pb.TagNumber(4) void clearGroupCount() => clearField(4); @$pb.TagNumber(5) $fixnum.Int64 get repeatCount => $_getI64(4); @$pb.TagNumber(5) set repeatCount($fixnum.Int64 v) { $_setInt64(4, v); } @$pb.TagNumber(5) $core.bool hasRepeatCount() => $_has(4); @$pb.TagNumber(5) void clearRepeatCount() => clearField(5); @$pb.TagNumber(6) $fixnum.Int64 get comboCount => $_getI64(5); @$pb.TagNumber(6) set comboCount($fixnum.Int64 v) { $_setInt64(5, v); } @$pb.TagNumber(6) $core.bool hasComboCount() => $_has(5); @$pb.TagNumber(6) void clearComboCount() => clearField(6); @$pb.TagNumber(7) User get user => $_getN(6); @$pb.TagNumber(7) set user(User v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasUser() => $_has(6); @$pb.TagNumber(7) void clearUser() => clearField(7); @$pb.TagNumber(7) User ensureUser() => $_ensure(6); @$pb.TagNumber(8) User get toUser => $_getN(7); @$pb.TagNumber(8) set toUser(User v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasToUser() => $_has(7); @$pb.TagNumber(8) void clearToUser() => clearField(8); @$pb.TagNumber(8) User ensureToUser() => $_ensure(7); @$pb.TagNumber(9) $core.int get repeatEnd => $_getIZ(8); @$pb.TagNumber(9) set repeatEnd($core.int v) { $_setUnsignedInt32(8, v); } @$pb.TagNumber(9) $core.bool hasRepeatEnd() => $_has(8); @$pb.TagNumber(9) void clearRepeatEnd() => clearField(9); @$pb.TagNumber(10) TextEffect get textEffect => $_getN(9); @$pb.TagNumber(10) set textEffect(TextEffect v) { setField(10, v); } @$pb.TagNumber(10) $core.bool hasTextEffect() => $_has(9); @$pb.TagNumber(10) void clearTextEffect() => clearField(10); @$pb.TagNumber(10) TextEffect ensureTextEffect() => $_ensure(9); @$pb.TagNumber(11) $fixnum.Int64 get groupId => $_getI64(10); @$pb.TagNumber(11) set groupId($fixnum.Int64 v) { $_setInt64(10, v); } @$pb.TagNumber(11) $core.bool hasGroupId() => $_has(10); @$pb.TagNumber(11) void clearGroupId() => clearField(11); @$pb.TagNumber(12) $fixnum.Int64 get incomeTaskgifts => $_getI64(11); @$pb.TagNumber(12) set incomeTaskgifts($fixnum.Int64 v) { $_setInt64(11, v); } @$pb.TagNumber(12) $core.bool hasIncomeTaskgifts() => $_has(11); @$pb.TagNumber(12) void clearIncomeTaskgifts() => clearField(12); @$pb.TagNumber(13) $fixnum.Int64 get roomFanTicketCount => $_getI64(12); @$pb.TagNumber(13) set roomFanTicketCount($fixnum.Int64 v) { $_setInt64(12, v); } @$pb.TagNumber(13) $core.bool hasRoomFanTicketCount() => $_has(12); @$pb.TagNumber(13) void clearRoomFanTicketCount() => clearField(13); @$pb.TagNumber(14) GiftIMPriority get priority => $_getN(13); @$pb.TagNumber(14) set priority(GiftIMPriority v) { setField(14, v); } @$pb.TagNumber(14) $core.bool hasPriority() => $_has(13); @$pb.TagNumber(14) void clearPriority() => clearField(14); @$pb.TagNumber(14) GiftIMPriority ensurePriority() => $_ensure(13); @$pb.TagNumber(15) GiftStruct get gift => $_getN(14); @$pb.TagNumber(15) set gift(GiftStruct v) { setField(15, v); } @$pb.TagNumber(15) $core.bool hasGift() => $_has(14); @$pb.TagNumber(15) void clearGift() => clearField(15); @$pb.TagNumber(15) GiftStruct ensureGift() => $_ensure(14); @$pb.TagNumber(16) $core.String get logId => $_getSZ(15); @$pb.TagNumber(16) set logId($core.String v) { $_setString(15, v); } @$pb.TagNumber(16) $core.bool hasLogId() => $_has(15); @$pb.TagNumber(16) void clearLogId() => clearField(16); @$pb.TagNumber(17) $fixnum.Int64 get sendType => $_getI64(16); @$pb.TagNumber(17) set sendType($fixnum.Int64 v) { $_setInt64(16, v); } @$pb.TagNumber(17) $core.bool hasSendType() => $_has(16); @$pb.TagNumber(17) void clearSendType() => clearField(17); @$pb.TagNumber(18) PublicAreaCommon get publicAreaCommon => $_getN(17); @$pb.TagNumber(18) set publicAreaCommon(PublicAreaCommon v) { setField(18, v); } @$pb.TagNumber(18) $core.bool hasPublicAreaCommon() => $_has(17); @$pb.TagNumber(18) void clearPublicAreaCommon() => clearField(18); @$pb.TagNumber(18) PublicAreaCommon ensurePublicAreaCommon() => $_ensure(17); @$pb.TagNumber(19) Text get trayDisplayText => $_getN(18); @$pb.TagNumber(19) set trayDisplayText(Text v) { setField(19, v); } @$pb.TagNumber(19) $core.bool hasTrayDisplayText() => $_has(18); @$pb.TagNumber(19) void clearTrayDisplayText() => clearField(19); @$pb.TagNumber(19) Text ensureTrayDisplayText() => $_ensure(18); @$pb.TagNumber(20) $fixnum.Int64 get bannedDisplayEffects => $_getI64(19); @$pb.TagNumber(20) set bannedDisplayEffects($fixnum.Int64 v) { $_setInt64(19, v); } @$pb.TagNumber(20) $core.bool hasBannedDisplayEffects() => $_has(19); @$pb.TagNumber(20) void clearBannedDisplayEffects() => clearField(20); @$pb.TagNumber(25) $core.bool get displayForSelf => $_getBF(20); @$pb.TagNumber(25) set displayForSelf($core.bool v) { $_setBool(20, v); } @$pb.TagNumber(25) $core.bool hasDisplayForSelf() => $_has(20); @$pb.TagNumber(25) void clearDisplayForSelf() => clearField(25); @$pb.TagNumber(26) $core.String get interactGiftInfo => $_getSZ(21); @$pb.TagNumber(26) set interactGiftInfo($core.String v) { $_setString(21, v); } @$pb.TagNumber(26) $core.bool hasInteractGiftInfo() => $_has(21); @$pb.TagNumber(26) void clearInteractGiftInfo() => clearField(26); @$pb.TagNumber(27) $core.String get diyItemInfo => $_getSZ(22); @$pb.TagNumber(27) set diyItemInfo($core.String v) { $_setString(22, v); } @$pb.TagNumber(27) $core.bool hasDiyItemInfo() => $_has(22); @$pb.TagNumber(27) void clearDiyItemInfo() => clearField(27); @$pb.TagNumber(28) $core.List<$fixnum.Int64> get minAssetSetList => $_getList(23); @$pb.TagNumber(29) $fixnum.Int64 get totalCount => $_getI64(24); @$pb.TagNumber(29) set totalCount($fixnum.Int64 v) { $_setInt64(24, v); } @$pb.TagNumber(29) $core.bool hasTotalCount() => $_has(24); @$pb.TagNumber(29) void clearTotalCount() => clearField(29); @$pb.TagNumber(30) $core.int get clientGiftSource => $_getIZ(25); @$pb.TagNumber(30) set clientGiftSource($core.int v) { $_setUnsignedInt32(25, v); } @$pb.TagNumber(30) $core.bool hasClientGiftSource() => $_has(25); @$pb.TagNumber(30) void clearClientGiftSource() => clearField(30); @$pb.TagNumber(32) $core.List<$fixnum.Int64> get toUserIdsList => $_getList(26); @$pb.TagNumber(33) $fixnum.Int64 get sendTime => $_getI64(27); @$pb.TagNumber(33) set sendTime($fixnum.Int64 v) { $_setInt64(27, v); } @$pb.TagNumber(33) $core.bool hasSendTime() => $_has(27); @$pb.TagNumber(33) void clearSendTime() => clearField(33); @$pb.TagNumber(34) $fixnum.Int64 get forceDisplayEffects => $_getI64(28); @$pb.TagNumber(34) set forceDisplayEffects($fixnum.Int64 v) { $_setInt64(28, v); } @$pb.TagNumber(34) $core.bool hasForceDisplayEffects() => $_has(28); @$pb.TagNumber(34) void clearForceDisplayEffects() => clearField(34); @$pb.TagNumber(35) $core.String get traceId => $_getSZ(29); @$pb.TagNumber(35) set traceId($core.String v) { $_setString(29, v); } @$pb.TagNumber(35) $core.bool hasTraceId() => $_has(29); @$pb.TagNumber(35) void clearTraceId() => clearField(35); @$pb.TagNumber(36) $fixnum.Int64 get effectDisplayTs => $_getI64(30); @$pb.TagNumber(36) set effectDisplayTs($fixnum.Int64 v) { $_setInt64(30, v); } @$pb.TagNumber(36) $core.bool hasEffectDisplayTs() => $_has(30); @$pb.TagNumber(36) void clearEffectDisplayTs() => clearField(36); } class GiftStruct extends $pb.GeneratedMessage { factory GiftStruct() => create(); GiftStruct._() : super(); factory GiftStruct.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory GiftStruct.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GiftStruct', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'image', subBuilder: Image.create) ..aOS(2, _omitFieldNames ? '' : 'describe') ..aOB(3, _omitFieldNames ? '' : 'notify') ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'duration', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(7, _omitFieldNames ? '' : 'forLinkmic', protoName: 'forLinkmic') ..aOB(8, _omitFieldNames ? '' : 'doodle') ..aOB(9, _omitFieldNames ? '' : 'forFansclub', protoName: 'forFansclub') ..aOB(10, _omitFieldNames ? '' : 'combo') ..a<$core.int>(11, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OU3) ..a<$core.int>(12, _omitFieldNames ? '' : 'diamondCount', $pb.PbFieldType.OU3, protoName: 'diamondCount') ..aOB(13, _omitFieldNames ? '' : 'isDisplayedOnPanel', protoName: 'isDisplayedOnPanel') ..a<$fixnum.Int64>(14, _omitFieldNames ? '' : 'primaryEffectId', $pb.PbFieldType.OU6, protoName: 'primaryEffectId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(15, _omitFieldNames ? '' : 'giftLabelIcon', protoName: 'giftLabelIcon', subBuilder: Image.create) ..aOS(16, _omitFieldNames ? '' : 'name') ..aOS(17, _omitFieldNames ? '' : 'region') ..aOS(18, _omitFieldNames ? '' : 'manual') ..aOB(19, _omitFieldNames ? '' : 'forCustom', protoName: 'forCustom') ..aOM(21, _omitFieldNames ? '' : 'icon', subBuilder: Image.create) ..a<$core.int>(22, _omitFieldNames ? '' : 'actionType', $pb.PbFieldType.OU3, protoName: 'actionType') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') GiftStruct clone() => GiftStruct()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') GiftStruct copyWith(void Function(GiftStruct) updates) => super.copyWith((message) => updates(message as GiftStruct)) as GiftStruct; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static GiftStruct create() => GiftStruct._(); GiftStruct createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static GiftStruct getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static GiftStruct? _defaultInstance; @$pb.TagNumber(1) Image get image => $_getN(0); @$pb.TagNumber(1) set image(Image v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasImage() => $_has(0); @$pb.TagNumber(1) void clearImage() => clearField(1); @$pb.TagNumber(1) Image ensureImage() => $_ensure(0); @$pb.TagNumber(2) $core.String get describe => $_getSZ(1); @$pb.TagNumber(2) set describe($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasDescribe() => $_has(1); @$pb.TagNumber(2) void clearDescribe() => clearField(2); @$pb.TagNumber(3) $core.bool get notify => $_getBF(2); @$pb.TagNumber(3) set notify($core.bool v) { $_setBool(2, v); } @$pb.TagNumber(3) $core.bool hasNotify() => $_has(2); @$pb.TagNumber(3) void clearNotify() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get duration => $_getI64(3); @$pb.TagNumber(4) set duration($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasDuration() => $_has(3); @$pb.TagNumber(4) void clearDuration() => clearField(4); @$pb.TagNumber(5) $fixnum.Int64 get id => $_getI64(4); @$pb.TagNumber(5) set id($fixnum.Int64 v) { $_setInt64(4, v); } @$pb.TagNumber(5) $core.bool hasId() => $_has(4); @$pb.TagNumber(5) void clearId() => clearField(5); @$pb.TagNumber(7) $core.bool get forLinkmic => $_getBF(5); @$pb.TagNumber(7) set forLinkmic($core.bool v) { $_setBool(5, v); } @$pb.TagNumber(7) $core.bool hasForLinkmic() => $_has(5); @$pb.TagNumber(7) void clearForLinkmic() => clearField(7); @$pb.TagNumber(8) $core.bool get doodle => $_getBF(6); @$pb.TagNumber(8) set doodle($core.bool v) { $_setBool(6, v); } @$pb.TagNumber(8) $core.bool hasDoodle() => $_has(6); @$pb.TagNumber(8) void clearDoodle() => clearField(8); @$pb.TagNumber(9) $core.bool get forFansclub => $_getBF(7); @$pb.TagNumber(9) set forFansclub($core.bool v) { $_setBool(7, v); } @$pb.TagNumber(9) $core.bool hasForFansclub() => $_has(7); @$pb.TagNumber(9) void clearForFansclub() => clearField(9); @$pb.TagNumber(10) $core.bool get combo => $_getBF(8); @$pb.TagNumber(10) set combo($core.bool v) { $_setBool(8, v); } @$pb.TagNumber(10) $core.bool hasCombo() => $_has(8); @$pb.TagNumber(10) void clearCombo() => clearField(10); @$pb.TagNumber(11) $core.int get type => $_getIZ(9); @$pb.TagNumber(11) set type($core.int v) { $_setUnsignedInt32(9, v); } @$pb.TagNumber(11) $core.bool hasType() => $_has(9); @$pb.TagNumber(11) void clearType() => clearField(11); @$pb.TagNumber(12) $core.int get diamondCount => $_getIZ(10); @$pb.TagNumber(12) set diamondCount($core.int v) { $_setUnsignedInt32(10, v); } @$pb.TagNumber(12) $core.bool hasDiamondCount() => $_has(10); @$pb.TagNumber(12) void clearDiamondCount() => clearField(12); @$pb.TagNumber(13) $core.bool get isDisplayedOnPanel => $_getBF(11); @$pb.TagNumber(13) set isDisplayedOnPanel($core.bool v) { $_setBool(11, v); } @$pb.TagNumber(13) $core.bool hasIsDisplayedOnPanel() => $_has(11); @$pb.TagNumber(13) void clearIsDisplayedOnPanel() => clearField(13); @$pb.TagNumber(14) $fixnum.Int64 get primaryEffectId => $_getI64(12); @$pb.TagNumber(14) set primaryEffectId($fixnum.Int64 v) { $_setInt64(12, v); } @$pb.TagNumber(14) $core.bool hasPrimaryEffectId() => $_has(12); @$pb.TagNumber(14) void clearPrimaryEffectId() => clearField(14); @$pb.TagNumber(15) Image get giftLabelIcon => $_getN(13); @$pb.TagNumber(15) set giftLabelIcon(Image v) { setField(15, v); } @$pb.TagNumber(15) $core.bool hasGiftLabelIcon() => $_has(13); @$pb.TagNumber(15) void clearGiftLabelIcon() => clearField(15); @$pb.TagNumber(15) Image ensureGiftLabelIcon() => $_ensure(13); @$pb.TagNumber(16) $core.String get name => $_getSZ(14); @$pb.TagNumber(16) set name($core.String v) { $_setString(14, v); } @$pb.TagNumber(16) $core.bool hasName() => $_has(14); @$pb.TagNumber(16) void clearName() => clearField(16); @$pb.TagNumber(17) $core.String get region => $_getSZ(15); @$pb.TagNumber(17) set region($core.String v) { $_setString(15, v); } @$pb.TagNumber(17) $core.bool hasRegion() => $_has(15); @$pb.TagNumber(17) void clearRegion() => clearField(17); @$pb.TagNumber(18) $core.String get manual => $_getSZ(16); @$pb.TagNumber(18) set manual($core.String v) { $_setString(16, v); } @$pb.TagNumber(18) $core.bool hasManual() => $_has(16); @$pb.TagNumber(18) void clearManual() => clearField(18); @$pb.TagNumber(19) $core.bool get forCustom => $_getBF(17); @$pb.TagNumber(19) set forCustom($core.bool v) { $_setBool(17, v); } @$pb.TagNumber(19) $core.bool hasForCustom() => $_has(17); @$pb.TagNumber(19) void clearForCustom() => clearField(19); @$pb.TagNumber(21) Image get icon => $_getN(18); @$pb.TagNumber(21) set icon(Image v) { setField(21, v); } @$pb.TagNumber(21) $core.bool hasIcon() => $_has(18); @$pb.TagNumber(21) void clearIcon() => clearField(21); @$pb.TagNumber(21) Image ensureIcon() => $_ensure(18); @$pb.TagNumber(22) $core.int get actionType => $_getIZ(19); @$pb.TagNumber(22) set actionType($core.int v) { $_setUnsignedInt32(19, v); } @$pb.TagNumber(22) $core.bool hasActionType() => $_has(19); @$pb.TagNumber(22) void clearActionType() => clearField(22); } class GiftIMPriority extends $pb.GeneratedMessage { factory GiftIMPriority() => create(); GiftIMPriority._() : super(); factory GiftIMPriority.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory GiftIMPriority.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GiftIMPriority', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..p<$fixnum.Int64>(1, _omitFieldNames ? '' : 'queueSizesList', $pb.PbFieldType.KU6, protoName: 'queueSizesList') ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'selfQueuePriority', $pb.PbFieldType.OU6, protoName: 'selfQueuePriority', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'priority', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') GiftIMPriority clone() => GiftIMPriority()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') GiftIMPriority copyWith(void Function(GiftIMPriority) updates) => super.copyWith((message) => updates(message as GiftIMPriority)) as GiftIMPriority; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static GiftIMPriority create() => GiftIMPriority._(); GiftIMPriority createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static GiftIMPriority getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static GiftIMPriority? _defaultInstance; @$pb.TagNumber(1) $core.List<$fixnum.Int64> get queueSizesList => $_getList(0); @$pb.TagNumber(2) $fixnum.Int64 get selfQueuePriority => $_getI64(1); @$pb.TagNumber(2) set selfQueuePriority($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasSelfQueuePriority() => $_has(1); @$pb.TagNumber(2) void clearSelfQueuePriority() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get priority => $_getI64(2); @$pb.TagNumber(3) set priority($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasPriority() => $_has(2); @$pb.TagNumber(3) void clearPriority() => clearField(3); } class TextEffect extends $pb.GeneratedMessage { factory TextEffect() => create(); TextEffect._() : super(); factory TextEffect.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextEffect.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextEffect', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'portrait', subBuilder: TextEffectDetail.create) ..aOM(2, _omitFieldNames ? '' : 'landscape', subBuilder: TextEffectDetail.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextEffect clone() => TextEffect()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextEffect copyWith(void Function(TextEffect) updates) => super.copyWith((message) => updates(message as TextEffect)) as TextEffect; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextEffect create() => TextEffect._(); TextEffect createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextEffect getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextEffect? _defaultInstance; @$pb.TagNumber(1) TextEffectDetail get portrait => $_getN(0); @$pb.TagNumber(1) set portrait(TextEffectDetail v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasPortrait() => $_has(0); @$pb.TagNumber(1) void clearPortrait() => clearField(1); @$pb.TagNumber(1) TextEffectDetail ensurePortrait() => $_ensure(0); @$pb.TagNumber(2) TextEffectDetail get landscape => $_getN(1); @$pb.TagNumber(2) set landscape(TextEffectDetail v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasLandscape() => $_has(1); @$pb.TagNumber(2) void clearLandscape() => clearField(2); @$pb.TagNumber(2) TextEffectDetail ensureLandscape() => $_ensure(1); } class TextEffectDetail extends $pb.GeneratedMessage { factory TextEffectDetail() => create(); TextEffectDetail._() : super(); factory TextEffectDetail.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextEffectDetail.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextEffectDetail', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'text', subBuilder: Text.create) ..a<$core.int>(2, _omitFieldNames ? '' : 'textFontSize', $pb.PbFieldType.OU3, protoName: 'textFontSize') ..aOM(3, _omitFieldNames ? '' : 'background', subBuilder: Image.create) ..a<$core.int>(4, _omitFieldNames ? '' : 'start', $pb.PbFieldType.OU3) ..a<$core.int>(5, _omitFieldNames ? '' : 'duration', $pb.PbFieldType.OU3) ..a<$core.int>(6, _omitFieldNames ? '' : 'x', $pb.PbFieldType.OU3) ..a<$core.int>(7, _omitFieldNames ? '' : 'y', $pb.PbFieldType.OU3) ..a<$core.int>(8, _omitFieldNames ? '' : 'width', $pb.PbFieldType.OU3) ..a<$core.int>(9, _omitFieldNames ? '' : 'height', $pb.PbFieldType.OU3) ..a<$core.int>(10, _omitFieldNames ? '' : 'shadowDx', $pb.PbFieldType.OU3, protoName: 'shadowDx') ..a<$core.int>(11, _omitFieldNames ? '' : 'shadowDy', $pb.PbFieldType.OU3, protoName: 'shadowDy') ..a<$core.int>(12, _omitFieldNames ? '' : 'shadowRadius', $pb.PbFieldType.OU3, protoName: 'shadowRadius') ..aOS(13, _omitFieldNames ? '' : 'shadowColor', protoName: 'shadowColor') ..aOS(14, _omitFieldNames ? '' : 'strokeColor', protoName: 'strokeColor') ..a<$core.int>(15, _omitFieldNames ? '' : 'strokeWidth', $pb.PbFieldType.OU3, protoName: 'strokeWidth') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextEffectDetail clone() => TextEffectDetail()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextEffectDetail copyWith(void Function(TextEffectDetail) updates) => super.copyWith((message) => updates(message as TextEffectDetail)) as TextEffectDetail; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextEffectDetail create() => TextEffectDetail._(); TextEffectDetail createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextEffectDetail getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextEffectDetail? _defaultInstance; @$pb.TagNumber(1) Text get text => $_getN(0); @$pb.TagNumber(1) set text(Text v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasText() => $_has(0); @$pb.TagNumber(1) void clearText() => clearField(1); @$pb.TagNumber(1) Text ensureText() => $_ensure(0); @$pb.TagNumber(2) $core.int get textFontSize => $_getIZ(1); @$pb.TagNumber(2) set textFontSize($core.int v) { $_setUnsignedInt32(1, v); } @$pb.TagNumber(2) $core.bool hasTextFontSize() => $_has(1); @$pb.TagNumber(2) void clearTextFontSize() => clearField(2); @$pb.TagNumber(3) Image get background => $_getN(2); @$pb.TagNumber(3) set background(Image v) { setField(3, v); } @$pb.TagNumber(3) $core.bool hasBackground() => $_has(2); @$pb.TagNumber(3) void clearBackground() => clearField(3); @$pb.TagNumber(3) Image ensureBackground() => $_ensure(2); @$pb.TagNumber(4) $core.int get start => $_getIZ(3); @$pb.TagNumber(4) set start($core.int v) { $_setUnsignedInt32(3, v); } @$pb.TagNumber(4) $core.bool hasStart() => $_has(3); @$pb.TagNumber(4) void clearStart() => clearField(4); @$pb.TagNumber(5) $core.int get duration => $_getIZ(4); @$pb.TagNumber(5) set duration($core.int v) { $_setUnsignedInt32(4, v); } @$pb.TagNumber(5) $core.bool hasDuration() => $_has(4); @$pb.TagNumber(5) void clearDuration() => clearField(5); @$pb.TagNumber(6) $core.int get x => $_getIZ(5); @$pb.TagNumber(6) set x($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasX() => $_has(5); @$pb.TagNumber(6) void clearX() => clearField(6); @$pb.TagNumber(7) $core.int get y => $_getIZ(6); @$pb.TagNumber(7) set y($core.int v) { $_setUnsignedInt32(6, v); } @$pb.TagNumber(7) $core.bool hasY() => $_has(6); @$pb.TagNumber(7) void clearY() => clearField(7); @$pb.TagNumber(8) $core.int get width => $_getIZ(7); @$pb.TagNumber(8) set width($core.int v) { $_setUnsignedInt32(7, v); } @$pb.TagNumber(8) $core.bool hasWidth() => $_has(7); @$pb.TagNumber(8) void clearWidth() => clearField(8); @$pb.TagNumber(9) $core.int get height => $_getIZ(8); @$pb.TagNumber(9) set height($core.int v) { $_setUnsignedInt32(8, v); } @$pb.TagNumber(9) $core.bool hasHeight() => $_has(8); @$pb.TagNumber(9) void clearHeight() => clearField(9); @$pb.TagNumber(10) $core.int get shadowDx => $_getIZ(9); @$pb.TagNumber(10) set shadowDx($core.int v) { $_setUnsignedInt32(9, v); } @$pb.TagNumber(10) $core.bool hasShadowDx() => $_has(9); @$pb.TagNumber(10) void clearShadowDx() => clearField(10); @$pb.TagNumber(11) $core.int get shadowDy => $_getIZ(10); @$pb.TagNumber(11) set shadowDy($core.int v) { $_setUnsignedInt32(10, v); } @$pb.TagNumber(11) $core.bool hasShadowDy() => $_has(10); @$pb.TagNumber(11) void clearShadowDy() => clearField(11); @$pb.TagNumber(12) $core.int get shadowRadius => $_getIZ(11); @$pb.TagNumber(12) set shadowRadius($core.int v) { $_setUnsignedInt32(11, v); } @$pb.TagNumber(12) $core.bool hasShadowRadius() => $_has(11); @$pb.TagNumber(12) void clearShadowRadius() => clearField(12); @$pb.TagNumber(13) $core.String get shadowColor => $_getSZ(12); @$pb.TagNumber(13) set shadowColor($core.String v) { $_setString(12, v); } @$pb.TagNumber(13) $core.bool hasShadowColor() => $_has(12); @$pb.TagNumber(13) void clearShadowColor() => clearField(13); @$pb.TagNumber(14) $core.String get strokeColor => $_getSZ(13); @$pb.TagNumber(14) set strokeColor($core.String v) { $_setString(13, v); } @$pb.TagNumber(14) $core.bool hasStrokeColor() => $_has(13); @$pb.TagNumber(14) void clearStrokeColor() => clearField(14); @$pb.TagNumber(15) $core.int get strokeWidth => $_getIZ(14); @$pb.TagNumber(15) set strokeWidth($core.int v) { $_setUnsignedInt32(14, v); } @$pb.TagNumber(15) $core.bool hasStrokeWidth() => $_has(14); @$pb.TagNumber(15) void clearStrokeWidth() => clearField(15); } class MemberMessage extends $pb.GeneratedMessage { factory MemberMessage() => create(); MemberMessage._() : super(); factory MemberMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory MemberMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'MemberMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..aOM(2, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'memberCount', $pb.PbFieldType.OU6, protoName: 'memberCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(4, _omitFieldNames ? '' : 'operator', subBuilder: User.create) ..aOB(5, _omitFieldNames ? '' : 'isSetToAdmin', protoName: 'isSetToAdmin') ..aOB(6, _omitFieldNames ? '' : 'isTopUser', protoName: 'isTopUser') ..a<$fixnum.Int64>(7, _omitFieldNames ? '' : 'rankScore', $pb.PbFieldType.OU6, protoName: 'rankScore', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(8, _omitFieldNames ? '' : 'topUserNo', $pb.PbFieldType.OU6, protoName: 'topUserNo', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(9, _omitFieldNames ? '' : 'enterType', $pb.PbFieldType.OU6, protoName: 'enterType', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(10, _omitFieldNames ? '' : 'action', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(11, _omitFieldNames ? '' : 'actionDescription', protoName: 'actionDescription') ..a<$fixnum.Int64>(12, _omitFieldNames ? '' : 'userId', $pb.PbFieldType.OU6, protoName: 'userId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(13, _omitFieldNames ? '' : 'effectConfig', protoName: 'effectConfig', subBuilder: EffectConfig.create) ..aOS(14, _omitFieldNames ? '' : 'popStr', protoName: 'popStr') ..aOM(15, _omitFieldNames ? '' : 'enterEffectConfig', protoName: 'enterEffectConfig', subBuilder: EffectConfig.create) ..aOM(16, _omitFieldNames ? '' : 'backgroundImage', protoName: 'backgroundImage', subBuilder: Image.create) ..aOM(17, _omitFieldNames ? '' : 'backgroundImageV2', protoName: 'backgroundImageV2', subBuilder: Image.create) ..aOM(18, _omitFieldNames ? '' : 'anchorDisplayText', protoName: 'anchorDisplayText', subBuilder: Text.create) ..aOM(19, _omitFieldNames ? '' : 'publicAreaCommon', protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create) ..a<$fixnum.Int64>(20, _omitFieldNames ? '' : 'userEnterTipType', $pb.PbFieldType.OU6, protoName: 'userEnterTipType', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(21, _omitFieldNames ? '' : 'anchorEnterTipType', $pb.PbFieldType.OU6, protoName: 'anchorEnterTipType', defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') MemberMessage clone() => MemberMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') MemberMessage copyWith(void Function(MemberMessage) updates) => super.copyWith((message) => updates(message as MemberMessage)) as MemberMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static MemberMessage create() => MemberMessage._(); MemberMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static MemberMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static MemberMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) User get user => $_getN(1); @$pb.TagNumber(2) set user(User v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasUser() => $_has(1); @$pb.TagNumber(2) void clearUser() => clearField(2); @$pb.TagNumber(2) User ensureUser() => $_ensure(1); @$pb.TagNumber(3) $fixnum.Int64 get memberCount => $_getI64(2); @$pb.TagNumber(3) set memberCount($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasMemberCount() => $_has(2); @$pb.TagNumber(3) void clearMemberCount() => clearField(3); @$pb.TagNumber(4) User get operator => $_getN(3); @$pb.TagNumber(4) set operator(User v) { setField(4, v); } @$pb.TagNumber(4) $core.bool hasOperator() => $_has(3); @$pb.TagNumber(4) void clearOperator() => clearField(4); @$pb.TagNumber(4) User ensureOperator() => $_ensure(3); @$pb.TagNumber(5) $core.bool get isSetToAdmin => $_getBF(4); @$pb.TagNumber(5) set isSetToAdmin($core.bool v) { $_setBool(4, v); } @$pb.TagNumber(5) $core.bool hasIsSetToAdmin() => $_has(4); @$pb.TagNumber(5) void clearIsSetToAdmin() => clearField(5); @$pb.TagNumber(6) $core.bool get isTopUser => $_getBF(5); @$pb.TagNumber(6) set isTopUser($core.bool v) { $_setBool(5, v); } @$pb.TagNumber(6) $core.bool hasIsTopUser() => $_has(5); @$pb.TagNumber(6) void clearIsTopUser() => clearField(6); @$pb.TagNumber(7) $fixnum.Int64 get rankScore => $_getI64(6); @$pb.TagNumber(7) set rankScore($fixnum.Int64 v) { $_setInt64(6, v); } @$pb.TagNumber(7) $core.bool hasRankScore() => $_has(6); @$pb.TagNumber(7) void clearRankScore() => clearField(7); @$pb.TagNumber(8) $fixnum.Int64 get topUserNo => $_getI64(7); @$pb.TagNumber(8) set topUserNo($fixnum.Int64 v) { $_setInt64(7, v); } @$pb.TagNumber(8) $core.bool hasTopUserNo() => $_has(7); @$pb.TagNumber(8) void clearTopUserNo() => clearField(8); @$pb.TagNumber(9) $fixnum.Int64 get enterType => $_getI64(8); @$pb.TagNumber(9) set enterType($fixnum.Int64 v) { $_setInt64(8, v); } @$pb.TagNumber(9) $core.bool hasEnterType() => $_has(8); @$pb.TagNumber(9) void clearEnterType() => clearField(9); @$pb.TagNumber(10) $fixnum.Int64 get action => $_getI64(9); @$pb.TagNumber(10) set action($fixnum.Int64 v) { $_setInt64(9, v); } @$pb.TagNumber(10) $core.bool hasAction() => $_has(9); @$pb.TagNumber(10) void clearAction() => clearField(10); @$pb.TagNumber(11) $core.String get actionDescription => $_getSZ(10); @$pb.TagNumber(11) set actionDescription($core.String v) { $_setString(10, v); } @$pb.TagNumber(11) $core.bool hasActionDescription() => $_has(10); @$pb.TagNumber(11) void clearActionDescription() => clearField(11); @$pb.TagNumber(12) $fixnum.Int64 get userId => $_getI64(11); @$pb.TagNumber(12) set userId($fixnum.Int64 v) { $_setInt64(11, v); } @$pb.TagNumber(12) $core.bool hasUserId() => $_has(11); @$pb.TagNumber(12) void clearUserId() => clearField(12); @$pb.TagNumber(13) EffectConfig get effectConfig => $_getN(12); @$pb.TagNumber(13) set effectConfig(EffectConfig v) { setField(13, v); } @$pb.TagNumber(13) $core.bool hasEffectConfig() => $_has(12); @$pb.TagNumber(13) void clearEffectConfig() => clearField(13); @$pb.TagNumber(13) EffectConfig ensureEffectConfig() => $_ensure(12); @$pb.TagNumber(14) $core.String get popStr => $_getSZ(13); @$pb.TagNumber(14) set popStr($core.String v) { $_setString(13, v); } @$pb.TagNumber(14) $core.bool hasPopStr() => $_has(13); @$pb.TagNumber(14) void clearPopStr() => clearField(14); @$pb.TagNumber(15) EffectConfig get enterEffectConfig => $_getN(14); @$pb.TagNumber(15) set enterEffectConfig(EffectConfig v) { setField(15, v); } @$pb.TagNumber(15) $core.bool hasEnterEffectConfig() => $_has(14); @$pb.TagNumber(15) void clearEnterEffectConfig() => clearField(15); @$pb.TagNumber(15) EffectConfig ensureEnterEffectConfig() => $_ensure(14); @$pb.TagNumber(16) Image get backgroundImage => $_getN(15); @$pb.TagNumber(16) set backgroundImage(Image v) { setField(16, v); } @$pb.TagNumber(16) $core.bool hasBackgroundImage() => $_has(15); @$pb.TagNumber(16) void clearBackgroundImage() => clearField(16); @$pb.TagNumber(16) Image ensureBackgroundImage() => $_ensure(15); @$pb.TagNumber(17) Image get backgroundImageV2 => $_getN(16); @$pb.TagNumber(17) set backgroundImageV2(Image v) { setField(17, v); } @$pb.TagNumber(17) $core.bool hasBackgroundImageV2() => $_has(16); @$pb.TagNumber(17) void clearBackgroundImageV2() => clearField(17); @$pb.TagNumber(17) Image ensureBackgroundImageV2() => $_ensure(16); @$pb.TagNumber(18) Text get anchorDisplayText => $_getN(17); @$pb.TagNumber(18) set anchorDisplayText(Text v) { setField(18, v); } @$pb.TagNumber(18) $core.bool hasAnchorDisplayText() => $_has(17); @$pb.TagNumber(18) void clearAnchorDisplayText() => clearField(18); @$pb.TagNumber(18) Text ensureAnchorDisplayText() => $_ensure(17); @$pb.TagNumber(19) PublicAreaCommon get publicAreaCommon => $_getN(18); @$pb.TagNumber(19) set publicAreaCommon(PublicAreaCommon v) { setField(19, v); } @$pb.TagNumber(19) $core.bool hasPublicAreaCommon() => $_has(18); @$pb.TagNumber(19) void clearPublicAreaCommon() => clearField(19); @$pb.TagNumber(19) PublicAreaCommon ensurePublicAreaCommon() => $_ensure(18); @$pb.TagNumber(20) $fixnum.Int64 get userEnterTipType => $_getI64(19); @$pb.TagNumber(20) set userEnterTipType($fixnum.Int64 v) { $_setInt64(19, v); } @$pb.TagNumber(20) $core.bool hasUserEnterTipType() => $_has(19); @$pb.TagNumber(20) void clearUserEnterTipType() => clearField(20); @$pb.TagNumber(21) $fixnum.Int64 get anchorEnterTipType => $_getI64(20); @$pb.TagNumber(21) set anchorEnterTipType($fixnum.Int64 v) { $_setInt64(20, v); } @$pb.TagNumber(21) $core.bool hasAnchorEnterTipType() => $_has(20); @$pb.TagNumber(21) void clearAnchorEnterTipType() => clearField(21); } class PublicAreaCommon extends $pb.GeneratedMessage { factory PublicAreaCommon() => create(); PublicAreaCommon._() : super(); factory PublicAreaCommon.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory PublicAreaCommon.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PublicAreaCommon', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'userLabel', protoName: 'userLabel', subBuilder: Image.create) ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'userConsumeInRoom', $pb.PbFieldType.OU6, protoName: 'userConsumeInRoom', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'userSendGiftCntInRoom', $pb.PbFieldType.OU6, protoName: 'userSendGiftCntInRoom', defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') PublicAreaCommon clone() => PublicAreaCommon()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') PublicAreaCommon copyWith(void Function(PublicAreaCommon) updates) => super.copyWith((message) => updates(message as PublicAreaCommon)) as PublicAreaCommon; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PublicAreaCommon create() => PublicAreaCommon._(); PublicAreaCommon createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static PublicAreaCommon getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static PublicAreaCommon? _defaultInstance; @$pb.TagNumber(1) Image get userLabel => $_getN(0); @$pb.TagNumber(1) set userLabel(Image v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasUserLabel() => $_has(0); @$pb.TagNumber(1) void clearUserLabel() => clearField(1); @$pb.TagNumber(1) Image ensureUserLabel() => $_ensure(0); @$pb.TagNumber(2) $fixnum.Int64 get userConsumeInRoom => $_getI64(1); @$pb.TagNumber(2) set userConsumeInRoom($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasUserConsumeInRoom() => $_has(1); @$pb.TagNumber(2) void clearUserConsumeInRoom() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get userSendGiftCntInRoom => $_getI64(2); @$pb.TagNumber(3) set userSendGiftCntInRoom($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasUserSendGiftCntInRoom() => $_has(2); @$pb.TagNumber(3) void clearUserSendGiftCntInRoom() => clearField(3); } class EffectConfig extends $pb.GeneratedMessage { factory EffectConfig() => create(); EffectConfig._() : super(); factory EffectConfig.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory EffectConfig.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EffectConfig', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'type', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(2, _omitFieldNames ? '' : 'icon', subBuilder: Image.create) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'avatarPos', $pb.PbFieldType.OU6, protoName: 'avatarPos', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(4, _omitFieldNames ? '' : 'text', subBuilder: Text.create) ..aOM(5, _omitFieldNames ? '' : 'textIcon', protoName: 'textIcon', subBuilder: Image.create) ..a<$core.int>(6, _omitFieldNames ? '' : 'stayTime', $pb.PbFieldType.OU3, protoName: 'stayTime') ..a<$fixnum.Int64>(7, _omitFieldNames ? '' : 'animAssetId', $pb.PbFieldType.OU6, protoName: 'animAssetId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(8, _omitFieldNames ? '' : 'badge', subBuilder: Image.create) ..p<$fixnum.Int64>(9, _omitFieldNames ? '' : 'flexSettingArrayList', $pb.PbFieldType.KU6, protoName: 'flexSettingArrayList') ..aOM(10, _omitFieldNames ? '' : 'textIconOverlay', protoName: 'textIconOverlay', subBuilder: Image.create) ..aOM(11, _omitFieldNames ? '' : 'animatedBadge', protoName: 'animatedBadge', subBuilder: Image.create) ..aOB(12, _omitFieldNames ? '' : 'hasSweepLight', protoName: 'hasSweepLight') ..p<$fixnum.Int64>(13, _omitFieldNames ? '' : 'textFlexSettingArrayList', $pb.PbFieldType.KU6, protoName: 'textFlexSettingArrayList') ..a<$fixnum.Int64>(14, _omitFieldNames ? '' : 'centerAnimAssetId', $pb.PbFieldType.OU6, protoName: 'centerAnimAssetId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(15, _omitFieldNames ? '' : 'dynamicImage', protoName: 'dynamicImage', subBuilder: Image.create) ..m<$core.String, $core.String>(16, _omitFieldNames ? '' : 'extraMap', protoName: 'extraMap', entryClassName: 'EffectConfig.ExtraMapEntry', keyFieldType: $pb.PbFieldType.OS, valueFieldType: $pb.PbFieldType.OS, packageName: const $pb.PackageName('douyin')) ..a<$fixnum.Int64>(17, _omitFieldNames ? '' : 'mp4AnimAssetId', $pb.PbFieldType.OU6, protoName: 'mp4AnimAssetId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(18, _omitFieldNames ? '' : 'priority', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(19, _omitFieldNames ? '' : 'maxWaitTime', $pb.PbFieldType.OU6, protoName: 'maxWaitTime', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(20, _omitFieldNames ? '' : 'dressId', protoName: 'dressId') ..a<$fixnum.Int64>(21, _omitFieldNames ? '' : 'alignment', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(22, _omitFieldNames ? '' : 'alignmentOffset', $pb.PbFieldType.OU6, protoName: 'alignmentOffset', defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') EffectConfig clone() => EffectConfig()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') EffectConfig copyWith(void Function(EffectConfig) updates) => super.copyWith((message) => updates(message as EffectConfig)) as EffectConfig; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static EffectConfig create() => EffectConfig._(); EffectConfig createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static EffectConfig getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static EffectConfig? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get type => $_getI64(0); @$pb.TagNumber(1) set type($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasType() => $_has(0); @$pb.TagNumber(1) void clearType() => clearField(1); @$pb.TagNumber(2) Image get icon => $_getN(1); @$pb.TagNumber(2) set icon(Image v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasIcon() => $_has(1); @$pb.TagNumber(2) void clearIcon() => clearField(2); @$pb.TagNumber(2) Image ensureIcon() => $_ensure(1); @$pb.TagNumber(3) $fixnum.Int64 get avatarPos => $_getI64(2); @$pb.TagNumber(3) set avatarPos($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasAvatarPos() => $_has(2); @$pb.TagNumber(3) void clearAvatarPos() => clearField(3); @$pb.TagNumber(4) Text get text => $_getN(3); @$pb.TagNumber(4) set text(Text v) { setField(4, v); } @$pb.TagNumber(4) $core.bool hasText() => $_has(3); @$pb.TagNumber(4) void clearText() => clearField(4); @$pb.TagNumber(4) Text ensureText() => $_ensure(3); @$pb.TagNumber(5) Image get textIcon => $_getN(4); @$pb.TagNumber(5) set textIcon(Image v) { setField(5, v); } @$pb.TagNumber(5) $core.bool hasTextIcon() => $_has(4); @$pb.TagNumber(5) void clearTextIcon() => clearField(5); @$pb.TagNumber(5) Image ensureTextIcon() => $_ensure(4); @$pb.TagNumber(6) $core.int get stayTime => $_getIZ(5); @$pb.TagNumber(6) set stayTime($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasStayTime() => $_has(5); @$pb.TagNumber(6) void clearStayTime() => clearField(6); @$pb.TagNumber(7) $fixnum.Int64 get animAssetId => $_getI64(6); @$pb.TagNumber(7) set animAssetId($fixnum.Int64 v) { $_setInt64(6, v); } @$pb.TagNumber(7) $core.bool hasAnimAssetId() => $_has(6); @$pb.TagNumber(7) void clearAnimAssetId() => clearField(7); @$pb.TagNumber(8) Image get badge => $_getN(7); @$pb.TagNumber(8) set badge(Image v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasBadge() => $_has(7); @$pb.TagNumber(8) void clearBadge() => clearField(8); @$pb.TagNumber(8) Image ensureBadge() => $_ensure(7); @$pb.TagNumber(9) $core.List<$fixnum.Int64> get flexSettingArrayList => $_getList(8); @$pb.TagNumber(10) Image get textIconOverlay => $_getN(9); @$pb.TagNumber(10) set textIconOverlay(Image v) { setField(10, v); } @$pb.TagNumber(10) $core.bool hasTextIconOverlay() => $_has(9); @$pb.TagNumber(10) void clearTextIconOverlay() => clearField(10); @$pb.TagNumber(10) Image ensureTextIconOverlay() => $_ensure(9); @$pb.TagNumber(11) Image get animatedBadge => $_getN(10); @$pb.TagNumber(11) set animatedBadge(Image v) { setField(11, v); } @$pb.TagNumber(11) $core.bool hasAnimatedBadge() => $_has(10); @$pb.TagNumber(11) void clearAnimatedBadge() => clearField(11); @$pb.TagNumber(11) Image ensureAnimatedBadge() => $_ensure(10); @$pb.TagNumber(12) $core.bool get hasSweepLight => $_getBF(11); @$pb.TagNumber(12) set hasSweepLight($core.bool v) { $_setBool(11, v); } @$pb.TagNumber(12) $core.bool hasHasSweepLight() => $_has(11); @$pb.TagNumber(12) void clearHasSweepLight() => clearField(12); @$pb.TagNumber(13) $core.List<$fixnum.Int64> get textFlexSettingArrayList => $_getList(12); @$pb.TagNumber(14) $fixnum.Int64 get centerAnimAssetId => $_getI64(13); @$pb.TagNumber(14) set centerAnimAssetId($fixnum.Int64 v) { $_setInt64(13, v); } @$pb.TagNumber(14) $core.bool hasCenterAnimAssetId() => $_has(13); @$pb.TagNumber(14) void clearCenterAnimAssetId() => clearField(14); @$pb.TagNumber(15) Image get dynamicImage => $_getN(14); @$pb.TagNumber(15) set dynamicImage(Image v) { setField(15, v); } @$pb.TagNumber(15) $core.bool hasDynamicImage() => $_has(14); @$pb.TagNumber(15) void clearDynamicImage() => clearField(15); @$pb.TagNumber(15) Image ensureDynamicImage() => $_ensure(14); @$pb.TagNumber(16) $core.Map<$core.String, $core.String> get extraMap => $_getMap(15); @$pb.TagNumber(17) $fixnum.Int64 get mp4AnimAssetId => $_getI64(16); @$pb.TagNumber(17) set mp4AnimAssetId($fixnum.Int64 v) { $_setInt64(16, v); } @$pb.TagNumber(17) $core.bool hasMp4AnimAssetId() => $_has(16); @$pb.TagNumber(17) void clearMp4AnimAssetId() => clearField(17); @$pb.TagNumber(18) $fixnum.Int64 get priority => $_getI64(17); @$pb.TagNumber(18) set priority($fixnum.Int64 v) { $_setInt64(17, v); } @$pb.TagNumber(18) $core.bool hasPriority() => $_has(17); @$pb.TagNumber(18) void clearPriority() => clearField(18); @$pb.TagNumber(19) $fixnum.Int64 get maxWaitTime => $_getI64(18); @$pb.TagNumber(19) set maxWaitTime($fixnum.Int64 v) { $_setInt64(18, v); } @$pb.TagNumber(19) $core.bool hasMaxWaitTime() => $_has(18); @$pb.TagNumber(19) void clearMaxWaitTime() => clearField(19); @$pb.TagNumber(20) $core.String get dressId => $_getSZ(19); @$pb.TagNumber(20) set dressId($core.String v) { $_setString(19, v); } @$pb.TagNumber(20) $core.bool hasDressId() => $_has(19); @$pb.TagNumber(20) void clearDressId() => clearField(20); @$pb.TagNumber(21) $fixnum.Int64 get alignment => $_getI64(20); @$pb.TagNumber(21) set alignment($fixnum.Int64 v) { $_setInt64(20, v); } @$pb.TagNumber(21) $core.bool hasAlignment() => $_has(20); @$pb.TagNumber(21) void clearAlignment() => clearField(21); @$pb.TagNumber(22) $fixnum.Int64 get alignmentOffset => $_getI64(21); @$pb.TagNumber(22) set alignmentOffset($fixnum.Int64 v) { $_setInt64(21, v); } @$pb.TagNumber(22) $core.bool hasAlignmentOffset() => $_has(21); @$pb.TagNumber(22) void clearAlignmentOffset() => clearField(22); } class Text extends $pb.GeneratedMessage { factory Text() => create(); Text._() : super(); factory Text.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Text.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Text', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'key') ..aOS(2, _omitFieldNames ? '' : 'defaultPatter', protoName: 'defaultPatter') ..aOM(3, _omitFieldNames ? '' : 'defaultFormat', protoName: 'defaultFormat', subBuilder: TextFormat.create) ..pc(4, _omitFieldNames ? '' : 'piecesList', $pb.PbFieldType.PM, protoName: 'piecesList', subBuilder: TextPiece.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Text clone() => Text()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Text copyWith(void Function(Text) updates) => super.copyWith((message) => updates(message as Text)) as Text; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Text create() => Text._(); Text createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Text getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Text? _defaultInstance; @$pb.TagNumber(1) $core.String get key => $_getSZ(0); @$pb.TagNumber(1) set key($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasKey() => $_has(0); @$pb.TagNumber(1) void clearKey() => clearField(1); @$pb.TagNumber(2) $core.String get defaultPatter => $_getSZ(1); @$pb.TagNumber(2) set defaultPatter($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasDefaultPatter() => $_has(1); @$pb.TagNumber(2) void clearDefaultPatter() => clearField(2); @$pb.TagNumber(3) TextFormat get defaultFormat => $_getN(2); @$pb.TagNumber(3) set defaultFormat(TextFormat v) { setField(3, v); } @$pb.TagNumber(3) $core.bool hasDefaultFormat() => $_has(2); @$pb.TagNumber(3) void clearDefaultFormat() => clearField(3); @$pb.TagNumber(3) TextFormat ensureDefaultFormat() => $_ensure(2); @$pb.TagNumber(4) $core.List get piecesList => $_getList(3); } class TextPiece extends $pb.GeneratedMessage { factory TextPiece() => create(); TextPiece._() : super(); factory TextPiece.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextPiece.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextPiece', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOB(1, _omitFieldNames ? '' : 'type') ..aOM(2, _omitFieldNames ? '' : 'format', subBuilder: TextFormat.create) ..aOS(3, _omitFieldNames ? '' : 'stringValue', protoName: 'stringValue') ..aOM(4, _omitFieldNames ? '' : 'userValue', protoName: 'userValue', subBuilder: TextPieceUser.create) ..aOM(5, _omitFieldNames ? '' : 'giftValue', protoName: 'giftValue', subBuilder: TextPieceGift.create) ..aOM(6, _omitFieldNames ? '' : 'heartValue', protoName: 'heartValue', subBuilder: TextPieceHeart.create) ..aOM(7, _omitFieldNames ? '' : 'patternRefValue', protoName: 'patternRefValue', subBuilder: TextPiecePatternRef.create) ..aOM(8, _omitFieldNames ? '' : 'imageValue', protoName: 'imageValue', subBuilder: TextPieceImage.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextPiece clone() => TextPiece()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextPiece copyWith(void Function(TextPiece) updates) => super.copyWith((message) => updates(message as TextPiece)) as TextPiece; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextPiece create() => TextPiece._(); TextPiece createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextPiece getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextPiece? _defaultInstance; @$pb.TagNumber(1) $core.bool get type => $_getBF(0); @$pb.TagNumber(1) set type($core.bool v) { $_setBool(0, v); } @$pb.TagNumber(1) $core.bool hasType() => $_has(0); @$pb.TagNumber(1) void clearType() => clearField(1); @$pb.TagNumber(2) TextFormat get format => $_getN(1); @$pb.TagNumber(2) set format(TextFormat v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasFormat() => $_has(1); @$pb.TagNumber(2) void clearFormat() => clearField(2); @$pb.TagNumber(2) TextFormat ensureFormat() => $_ensure(1); @$pb.TagNumber(3) $core.String get stringValue => $_getSZ(2); @$pb.TagNumber(3) set stringValue($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasStringValue() => $_has(2); @$pb.TagNumber(3) void clearStringValue() => clearField(3); @$pb.TagNumber(4) TextPieceUser get userValue => $_getN(3); @$pb.TagNumber(4) set userValue(TextPieceUser v) { setField(4, v); } @$pb.TagNumber(4) $core.bool hasUserValue() => $_has(3); @$pb.TagNumber(4) void clearUserValue() => clearField(4); @$pb.TagNumber(4) TextPieceUser ensureUserValue() => $_ensure(3); @$pb.TagNumber(5) TextPieceGift get giftValue => $_getN(4); @$pb.TagNumber(5) set giftValue(TextPieceGift v) { setField(5, v); } @$pb.TagNumber(5) $core.bool hasGiftValue() => $_has(4); @$pb.TagNumber(5) void clearGiftValue() => clearField(5); @$pb.TagNumber(5) TextPieceGift ensureGiftValue() => $_ensure(4); @$pb.TagNumber(6) TextPieceHeart get heartValue => $_getN(5); @$pb.TagNumber(6) set heartValue(TextPieceHeart v) { setField(6, v); } @$pb.TagNumber(6) $core.bool hasHeartValue() => $_has(5); @$pb.TagNumber(6) void clearHeartValue() => clearField(6); @$pb.TagNumber(6) TextPieceHeart ensureHeartValue() => $_ensure(5); @$pb.TagNumber(7) TextPiecePatternRef get patternRefValue => $_getN(6); @$pb.TagNumber(7) set patternRefValue(TextPiecePatternRef v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasPatternRefValue() => $_has(6); @$pb.TagNumber(7) void clearPatternRefValue() => clearField(7); @$pb.TagNumber(7) TextPiecePatternRef ensurePatternRefValue() => $_ensure(6); @$pb.TagNumber(8) TextPieceImage get imageValue => $_getN(7); @$pb.TagNumber(8) set imageValue(TextPieceImage v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasImageValue() => $_has(7); @$pb.TagNumber(8) void clearImageValue() => clearField(8); @$pb.TagNumber(8) TextPieceImage ensureImageValue() => $_ensure(7); } class TextPieceImage extends $pb.GeneratedMessage { factory TextPieceImage() => create(); TextPieceImage._() : super(); factory TextPieceImage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextPieceImage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextPieceImage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'image', subBuilder: Image.create) ..a<$core.double>(2, _omitFieldNames ? '' : 'scalingRate', $pb.PbFieldType.OF, protoName: 'scalingRate') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextPieceImage clone() => TextPieceImage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextPieceImage copyWith(void Function(TextPieceImage) updates) => super.copyWith((message) => updates(message as TextPieceImage)) as TextPieceImage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextPieceImage create() => TextPieceImage._(); TextPieceImage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextPieceImage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextPieceImage? _defaultInstance; @$pb.TagNumber(1) Image get image => $_getN(0); @$pb.TagNumber(1) set image(Image v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasImage() => $_has(0); @$pb.TagNumber(1) void clearImage() => clearField(1); @$pb.TagNumber(1) Image ensureImage() => $_ensure(0); @$pb.TagNumber(2) $core.double get scalingRate => $_getN(1); @$pb.TagNumber(2) set scalingRate($core.double v) { $_setFloat(1, v); } @$pb.TagNumber(2) $core.bool hasScalingRate() => $_has(1); @$pb.TagNumber(2) void clearScalingRate() => clearField(2); } class TextPiecePatternRef extends $pb.GeneratedMessage { factory TextPiecePatternRef() => create(); TextPiecePatternRef._() : super(); factory TextPiecePatternRef.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextPiecePatternRef.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextPiecePatternRef', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'key') ..aOS(2, _omitFieldNames ? '' : 'defaultPattern', protoName: 'defaultPattern') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextPiecePatternRef clone() => TextPiecePatternRef()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextPiecePatternRef copyWith(void Function(TextPiecePatternRef) updates) => super.copyWith((message) => updates(message as TextPiecePatternRef)) as TextPiecePatternRef; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextPiecePatternRef create() => TextPiecePatternRef._(); TextPiecePatternRef createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextPiecePatternRef getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextPiecePatternRef? _defaultInstance; @$pb.TagNumber(1) $core.String get key => $_getSZ(0); @$pb.TagNumber(1) set key($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasKey() => $_has(0); @$pb.TagNumber(1) void clearKey() => clearField(1); @$pb.TagNumber(2) $core.String get defaultPattern => $_getSZ(1); @$pb.TagNumber(2) set defaultPattern($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasDefaultPattern() => $_has(1); @$pb.TagNumber(2) void clearDefaultPattern() => clearField(2); } class TextPieceHeart extends $pb.GeneratedMessage { factory TextPieceHeart() => create(); TextPieceHeart._() : super(); factory TextPieceHeart.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextPieceHeart.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextPieceHeart', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'color') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextPieceHeart clone() => TextPieceHeart()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextPieceHeart copyWith(void Function(TextPieceHeart) updates) => super.copyWith((message) => updates(message as TextPieceHeart)) as TextPieceHeart; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextPieceHeart create() => TextPieceHeart._(); TextPieceHeart createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextPieceHeart getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextPieceHeart? _defaultInstance; @$pb.TagNumber(1) $core.String get color => $_getSZ(0); @$pb.TagNumber(1) set color($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasColor() => $_has(0); @$pb.TagNumber(1) void clearColor() => clearField(1); } class TextPieceGift extends $pb.GeneratedMessage { factory TextPieceGift() => create(); TextPieceGift._() : super(); factory TextPieceGift.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextPieceGift.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextPieceGift', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'giftId', $pb.PbFieldType.OU6, protoName: 'giftId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(2, _omitFieldNames ? '' : 'nameRef', protoName: 'nameRef', subBuilder: PatternRef.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextPieceGift clone() => TextPieceGift()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextPieceGift copyWith(void Function(TextPieceGift) updates) => super.copyWith((message) => updates(message as TextPieceGift)) as TextPieceGift; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextPieceGift create() => TextPieceGift._(); TextPieceGift createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextPieceGift getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextPieceGift? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get giftId => $_getI64(0); @$pb.TagNumber(1) set giftId($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasGiftId() => $_has(0); @$pb.TagNumber(1) void clearGiftId() => clearField(1); @$pb.TagNumber(2) PatternRef get nameRef => $_getN(1); @$pb.TagNumber(2) set nameRef(PatternRef v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasNameRef() => $_has(1); @$pb.TagNumber(2) void clearNameRef() => clearField(2); @$pb.TagNumber(2) PatternRef ensureNameRef() => $_ensure(1); } class PatternRef extends $pb.GeneratedMessage { factory PatternRef() => create(); PatternRef._() : super(); factory PatternRef.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory PatternRef.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PatternRef', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'key') ..aOS(2, _omitFieldNames ? '' : 'defaultPattern', protoName: 'defaultPattern') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') PatternRef clone() => PatternRef()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') PatternRef copyWith(void Function(PatternRef) updates) => super.copyWith((message) => updates(message as PatternRef)) as PatternRef; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PatternRef create() => PatternRef._(); PatternRef createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static PatternRef getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static PatternRef? _defaultInstance; @$pb.TagNumber(1) $core.String get key => $_getSZ(0); @$pb.TagNumber(1) set key($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasKey() => $_has(0); @$pb.TagNumber(1) void clearKey() => clearField(1); @$pb.TagNumber(2) $core.String get defaultPattern => $_getSZ(1); @$pb.TagNumber(2) set defaultPattern($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasDefaultPattern() => $_has(1); @$pb.TagNumber(2) void clearDefaultPattern() => clearField(2); } class TextPieceUser extends $pb.GeneratedMessage { factory TextPieceUser() => create(); TextPieceUser._() : super(); factory TextPieceUser.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextPieceUser.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextPieceUser', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..aOB(2, _omitFieldNames ? '' : 'withColon', protoName: 'withColon') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextPieceUser clone() => TextPieceUser()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextPieceUser copyWith(void Function(TextPieceUser) updates) => super.copyWith((message) => updates(message as TextPieceUser)) as TextPieceUser; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextPieceUser create() => TextPieceUser._(); TextPieceUser createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextPieceUser getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextPieceUser? _defaultInstance; @$pb.TagNumber(1) User get user => $_getN(0); @$pb.TagNumber(1) set user(User v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasUser() => $_has(0); @$pb.TagNumber(1) void clearUser() => clearField(1); @$pb.TagNumber(1) User ensureUser() => $_ensure(0); @$pb.TagNumber(2) $core.bool get withColon => $_getBF(1); @$pb.TagNumber(2) set withColon($core.bool v) { $_setBool(1, v); } @$pb.TagNumber(2) $core.bool hasWithColon() => $_has(1); @$pb.TagNumber(2) void clearWithColon() => clearField(2); } class TextFormat extends $pb.GeneratedMessage { factory TextFormat() => create(); TextFormat._() : super(); factory TextFormat.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory TextFormat.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'TextFormat', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'color') ..aOB(2, _omitFieldNames ? '' : 'bold') ..aOB(3, _omitFieldNames ? '' : 'italic') ..a<$core.int>(4, _omitFieldNames ? '' : 'weight', $pb.PbFieldType.OU3) ..a<$core.int>(5, _omitFieldNames ? '' : 'italicAngle', $pb.PbFieldType.OU3, protoName: 'italicAngle') ..a<$core.int>(6, _omitFieldNames ? '' : 'fontSize', $pb.PbFieldType.OU3, protoName: 'fontSize') ..aOB(7, _omitFieldNames ? '' : 'useHeighLightColor', protoName: 'useHeighLightColor') ..aOB(8, _omitFieldNames ? '' : 'useRemoteClor', protoName: 'useRemoteClor') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') TextFormat clone() => TextFormat()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') TextFormat copyWith(void Function(TextFormat) updates) => super.copyWith((message) => updates(message as TextFormat)) as TextFormat; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static TextFormat create() => TextFormat._(); TextFormat createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static TextFormat getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static TextFormat? _defaultInstance; @$pb.TagNumber(1) $core.String get color => $_getSZ(0); @$pb.TagNumber(1) set color($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasColor() => $_has(0); @$pb.TagNumber(1) void clearColor() => clearField(1); @$pb.TagNumber(2) $core.bool get bold => $_getBF(1); @$pb.TagNumber(2) set bold($core.bool v) { $_setBool(1, v); } @$pb.TagNumber(2) $core.bool hasBold() => $_has(1); @$pb.TagNumber(2) void clearBold() => clearField(2); @$pb.TagNumber(3) $core.bool get italic => $_getBF(2); @$pb.TagNumber(3) set italic($core.bool v) { $_setBool(2, v); } @$pb.TagNumber(3) $core.bool hasItalic() => $_has(2); @$pb.TagNumber(3) void clearItalic() => clearField(3); @$pb.TagNumber(4) $core.int get weight => $_getIZ(3); @$pb.TagNumber(4) set weight($core.int v) { $_setUnsignedInt32(3, v); } @$pb.TagNumber(4) $core.bool hasWeight() => $_has(3); @$pb.TagNumber(4) void clearWeight() => clearField(4); @$pb.TagNumber(5) $core.int get italicAngle => $_getIZ(4); @$pb.TagNumber(5) set italicAngle($core.int v) { $_setUnsignedInt32(4, v); } @$pb.TagNumber(5) $core.bool hasItalicAngle() => $_has(4); @$pb.TagNumber(5) void clearItalicAngle() => clearField(5); @$pb.TagNumber(6) $core.int get fontSize => $_getIZ(5); @$pb.TagNumber(6) set fontSize($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasFontSize() => $_has(5); @$pb.TagNumber(6) void clearFontSize() => clearField(6); @$pb.TagNumber(7) $core.bool get useHeighLightColor => $_getBF(6); @$pb.TagNumber(7) set useHeighLightColor($core.bool v) { $_setBool(6, v); } @$pb.TagNumber(7) $core.bool hasUseHeighLightColor() => $_has(6); @$pb.TagNumber(7) void clearUseHeighLightColor() => clearField(7); @$pb.TagNumber(8) $core.bool get useRemoteClor => $_getBF(7); @$pb.TagNumber(8) set useRemoteClor($core.bool v) { $_setBool(7, v); } @$pb.TagNumber(8) $core.bool hasUseRemoteClor() => $_has(7); @$pb.TagNumber(8) void clearUseRemoteClor() => clearField(8); } class LikeMessage extends $pb.GeneratedMessage { factory LikeMessage() => create(); LikeMessage._() : super(); factory LikeMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory LikeMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'LikeMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'count', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'total', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'color', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(5, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..aOS(6, _omitFieldNames ? '' : 'icon') ..aOM(7, _omitFieldNames ? '' : 'doubleLikeDetail', protoName: 'doubleLikeDetail', subBuilder: DoubleLikeDetail.create) ..aOM(8, _omitFieldNames ? '' : 'displayControlInfo', protoName: 'displayControlInfo', subBuilder: DisplayControlInfo.create) ..a<$fixnum.Int64>(9, _omitFieldNames ? '' : 'linkmicGuestUid', $pb.PbFieldType.OU6, protoName: 'linkmicGuestUid', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(10, _omitFieldNames ? '' : 'scene') ..aOM(11, _omitFieldNames ? '' : 'picoDisplayInfo', protoName: 'picoDisplayInfo', subBuilder: PicoDisplayInfo.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') LikeMessage clone() => LikeMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') LikeMessage copyWith(void Function(LikeMessage) updates) => super.copyWith((message) => updates(message as LikeMessage)) as LikeMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static LikeMessage create() => LikeMessage._(); LikeMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static LikeMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static LikeMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) $fixnum.Int64 get count => $_getI64(1); @$pb.TagNumber(2) set count($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasCount() => $_has(1); @$pb.TagNumber(2) void clearCount() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get total => $_getI64(2); @$pb.TagNumber(3) set total($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasTotal() => $_has(2); @$pb.TagNumber(3) void clearTotal() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get color => $_getI64(3); @$pb.TagNumber(4) set color($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasColor() => $_has(3); @$pb.TagNumber(4) void clearColor() => clearField(4); @$pb.TagNumber(5) User get user => $_getN(4); @$pb.TagNumber(5) set user(User v) { setField(5, v); } @$pb.TagNumber(5) $core.bool hasUser() => $_has(4); @$pb.TagNumber(5) void clearUser() => clearField(5); @$pb.TagNumber(5) User ensureUser() => $_ensure(4); @$pb.TagNumber(6) $core.String get icon => $_getSZ(5); @$pb.TagNumber(6) set icon($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) $core.bool hasIcon() => $_has(5); @$pb.TagNumber(6) void clearIcon() => clearField(6); @$pb.TagNumber(7) DoubleLikeDetail get doubleLikeDetail => $_getN(6); @$pb.TagNumber(7) set doubleLikeDetail(DoubleLikeDetail v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasDoubleLikeDetail() => $_has(6); @$pb.TagNumber(7) void clearDoubleLikeDetail() => clearField(7); @$pb.TagNumber(7) DoubleLikeDetail ensureDoubleLikeDetail() => $_ensure(6); @$pb.TagNumber(8) DisplayControlInfo get displayControlInfo => $_getN(7); @$pb.TagNumber(8) set displayControlInfo(DisplayControlInfo v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasDisplayControlInfo() => $_has(7); @$pb.TagNumber(8) void clearDisplayControlInfo() => clearField(8); @$pb.TagNumber(8) DisplayControlInfo ensureDisplayControlInfo() => $_ensure(7); @$pb.TagNumber(9) $fixnum.Int64 get linkmicGuestUid => $_getI64(8); @$pb.TagNumber(9) set linkmicGuestUid($fixnum.Int64 v) { $_setInt64(8, v); } @$pb.TagNumber(9) $core.bool hasLinkmicGuestUid() => $_has(8); @$pb.TagNumber(9) void clearLinkmicGuestUid() => clearField(9); @$pb.TagNumber(10) $core.String get scene => $_getSZ(9); @$pb.TagNumber(10) set scene($core.String v) { $_setString(9, v); } @$pb.TagNumber(10) $core.bool hasScene() => $_has(9); @$pb.TagNumber(10) void clearScene() => clearField(10); @$pb.TagNumber(11) PicoDisplayInfo get picoDisplayInfo => $_getN(10); @$pb.TagNumber(11) set picoDisplayInfo(PicoDisplayInfo v) { setField(11, v); } @$pb.TagNumber(11) $core.bool hasPicoDisplayInfo() => $_has(10); @$pb.TagNumber(11) void clearPicoDisplayInfo() => clearField(11); @$pb.TagNumber(11) PicoDisplayInfo ensurePicoDisplayInfo() => $_ensure(10); } class SocialMessage extends $pb.GeneratedMessage { factory SocialMessage() => create(); SocialMessage._() : super(); factory SocialMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory SocialMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SocialMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..aOM(2, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'shareType', $pb.PbFieldType.OU6, protoName: 'shareType', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'action', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(5, _omitFieldNames ? '' : 'shareTarget', protoName: 'shareTarget') ..a<$fixnum.Int64>(6, _omitFieldNames ? '' : 'followCount', $pb.PbFieldType.OU6, protoName: 'followCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOM(7, _omitFieldNames ? '' : 'publicAreaCommon', protoName: 'publicAreaCommon', subBuilder: PublicAreaCommon.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') SocialMessage clone() => SocialMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') SocialMessage copyWith(void Function(SocialMessage) updates) => super.copyWith((message) => updates(message as SocialMessage)) as SocialMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static SocialMessage create() => SocialMessage._(); SocialMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static SocialMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static SocialMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) User get user => $_getN(1); @$pb.TagNumber(2) set user(User v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasUser() => $_has(1); @$pb.TagNumber(2) void clearUser() => clearField(2); @$pb.TagNumber(2) User ensureUser() => $_ensure(1); @$pb.TagNumber(3) $fixnum.Int64 get shareType => $_getI64(2); @$pb.TagNumber(3) set shareType($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasShareType() => $_has(2); @$pb.TagNumber(3) void clearShareType() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get action => $_getI64(3); @$pb.TagNumber(4) set action($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasAction() => $_has(3); @$pb.TagNumber(4) void clearAction() => clearField(4); @$pb.TagNumber(5) $core.String get shareTarget => $_getSZ(4); @$pb.TagNumber(5) set shareTarget($core.String v) { $_setString(4, v); } @$pb.TagNumber(5) $core.bool hasShareTarget() => $_has(4); @$pb.TagNumber(5) void clearShareTarget() => clearField(5); @$pb.TagNumber(6) $fixnum.Int64 get followCount => $_getI64(5); @$pb.TagNumber(6) set followCount($fixnum.Int64 v) { $_setInt64(5, v); } @$pb.TagNumber(6) $core.bool hasFollowCount() => $_has(5); @$pb.TagNumber(6) void clearFollowCount() => clearField(6); @$pb.TagNumber(7) PublicAreaCommon get publicAreaCommon => $_getN(6); @$pb.TagNumber(7) set publicAreaCommon(PublicAreaCommon v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasPublicAreaCommon() => $_has(6); @$pb.TagNumber(7) void clearPublicAreaCommon() => clearField(7); @$pb.TagNumber(7) PublicAreaCommon ensurePublicAreaCommon() => $_ensure(6); } class PicoDisplayInfo extends $pb.GeneratedMessage { factory PicoDisplayInfo() => create(); PicoDisplayInfo._() : super(); factory PicoDisplayInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory PicoDisplayInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PicoDisplayInfo', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'comboSumCount', $pb.PbFieldType.OU6, protoName: 'comboSumCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(2, _omitFieldNames ? '' : 'emoji') ..aOM(3, _omitFieldNames ? '' : 'emojiIcon', protoName: 'emojiIcon', subBuilder: Image.create) ..aOS(4, _omitFieldNames ? '' : 'emojiText', protoName: 'emojiText') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') PicoDisplayInfo clone() => PicoDisplayInfo()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') PicoDisplayInfo copyWith(void Function(PicoDisplayInfo) updates) => super.copyWith((message) => updates(message as PicoDisplayInfo)) as PicoDisplayInfo; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PicoDisplayInfo create() => PicoDisplayInfo._(); PicoDisplayInfo createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static PicoDisplayInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static PicoDisplayInfo? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get comboSumCount => $_getI64(0); @$pb.TagNumber(1) set comboSumCount($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasComboSumCount() => $_has(0); @$pb.TagNumber(1) void clearComboSumCount() => clearField(1); @$pb.TagNumber(2) $core.String get emoji => $_getSZ(1); @$pb.TagNumber(2) set emoji($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasEmoji() => $_has(1); @$pb.TagNumber(2) void clearEmoji() => clearField(2); @$pb.TagNumber(3) Image get emojiIcon => $_getN(2); @$pb.TagNumber(3) set emojiIcon(Image v) { setField(3, v); } @$pb.TagNumber(3) $core.bool hasEmojiIcon() => $_has(2); @$pb.TagNumber(3) void clearEmojiIcon() => clearField(3); @$pb.TagNumber(3) Image ensureEmojiIcon() => $_ensure(2); @$pb.TagNumber(4) $core.String get emojiText => $_getSZ(3); @$pb.TagNumber(4) set emojiText($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasEmojiText() => $_has(3); @$pb.TagNumber(4) void clearEmojiText() => clearField(4); } class DoubleLikeDetail extends $pb.GeneratedMessage { factory DoubleLikeDetail() => create(); DoubleLikeDetail._() : super(); factory DoubleLikeDetail.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory DoubleLikeDetail.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DoubleLikeDetail', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOB(1, _omitFieldNames ? '' : 'doubleFlag', protoName: 'doubleFlag') ..a<$core.int>(2, _omitFieldNames ? '' : 'seqId', $pb.PbFieldType.OU3, protoName: 'seqId') ..a<$core.int>(3, _omitFieldNames ? '' : 'renewalsNum', $pb.PbFieldType.OU3, protoName: 'renewalsNum') ..a<$core.int>(4, _omitFieldNames ? '' : 'triggersNum', $pb.PbFieldType.OU3, protoName: 'triggersNum') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') DoubleLikeDetail clone() => DoubleLikeDetail()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') DoubleLikeDetail copyWith(void Function(DoubleLikeDetail) updates) => super.copyWith((message) => updates(message as DoubleLikeDetail)) as DoubleLikeDetail; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static DoubleLikeDetail create() => DoubleLikeDetail._(); DoubleLikeDetail createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static DoubleLikeDetail getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static DoubleLikeDetail? _defaultInstance; @$pb.TagNumber(1) $core.bool get doubleFlag => $_getBF(0); @$pb.TagNumber(1) set doubleFlag($core.bool v) { $_setBool(0, v); } @$pb.TagNumber(1) $core.bool hasDoubleFlag() => $_has(0); @$pb.TagNumber(1) void clearDoubleFlag() => clearField(1); @$pb.TagNumber(2) $core.int get seqId => $_getIZ(1); @$pb.TagNumber(2) set seqId($core.int v) { $_setUnsignedInt32(1, v); } @$pb.TagNumber(2) $core.bool hasSeqId() => $_has(1); @$pb.TagNumber(2) void clearSeqId() => clearField(2); @$pb.TagNumber(3) $core.int get renewalsNum => $_getIZ(2); @$pb.TagNumber(3) set renewalsNum($core.int v) { $_setUnsignedInt32(2, v); } @$pb.TagNumber(3) $core.bool hasRenewalsNum() => $_has(2); @$pb.TagNumber(3) void clearRenewalsNum() => clearField(3); @$pb.TagNumber(4) $core.int get triggersNum => $_getIZ(3); @$pb.TagNumber(4) set triggersNum($core.int v) { $_setUnsignedInt32(3, v); } @$pb.TagNumber(4) $core.bool hasTriggersNum() => $_has(3); @$pb.TagNumber(4) void clearTriggersNum() => clearField(4); } class DisplayControlInfo extends $pb.GeneratedMessage { factory DisplayControlInfo() => create(); DisplayControlInfo._() : super(); factory DisplayControlInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory DisplayControlInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DisplayControlInfo', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOB(1, _omitFieldNames ? '' : 'showText', protoName: 'showText') ..aOB(2, _omitFieldNames ? '' : 'showIcons', protoName: 'showIcons') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') DisplayControlInfo clone() => DisplayControlInfo()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') DisplayControlInfo copyWith(void Function(DisplayControlInfo) updates) => super.copyWith((message) => updates(message as DisplayControlInfo)) as DisplayControlInfo; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static DisplayControlInfo create() => DisplayControlInfo._(); DisplayControlInfo createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static DisplayControlInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static DisplayControlInfo? _defaultInstance; @$pb.TagNumber(1) $core.bool get showText => $_getBF(0); @$pb.TagNumber(1) set showText($core.bool v) { $_setBool(0, v); } @$pb.TagNumber(1) $core.bool hasShowText() => $_has(0); @$pb.TagNumber(1) void clearShowText() => clearField(1); @$pb.TagNumber(2) $core.bool get showIcons => $_getBF(1); @$pb.TagNumber(2) set showIcons($core.bool v) { $_setBool(1, v); } @$pb.TagNumber(2) $core.bool hasShowIcons() => $_has(1); @$pb.TagNumber(2) void clearShowIcons() => clearField(2); } class EpisodeChatMessage extends $pb.GeneratedMessage { factory EpisodeChatMessage() => create(); EpisodeChatMessage._() : super(); factory EpisodeChatMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory EpisodeChatMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'EpisodeChatMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Message.create) ..aOM(2, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..aOS(3, _omitFieldNames ? '' : 'content') ..aOB(4, _omitFieldNames ? '' : 'visibleToSende', protoName: 'visibleToSende') ..aOM(7, _omitFieldNames ? '' : 'giftImage', protoName: 'giftImage', subBuilder: Image.create) ..a<$fixnum.Int64>(8, _omitFieldNames ? '' : 'agreeMsgId', $pb.PbFieldType.OU6, protoName: 'agreeMsgId', defaultOrMaker: $fixnum.Int64.ZERO) ..pPS(9, _omitFieldNames ? '' : 'colorValueList', protoName: 'colorValueList') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') EpisodeChatMessage clone() => EpisodeChatMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') EpisodeChatMessage copyWith(void Function(EpisodeChatMessage) updates) => super.copyWith((message) => updates(message as EpisodeChatMessage)) as EpisodeChatMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static EpisodeChatMessage create() => EpisodeChatMessage._(); EpisodeChatMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static EpisodeChatMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static EpisodeChatMessage? _defaultInstance; @$pb.TagNumber(1) Message get common => $_getN(0); @$pb.TagNumber(1) set common(Message v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Message ensureCommon() => $_ensure(0); @$pb.TagNumber(2) User get user => $_getN(1); @$pb.TagNumber(2) set user(User v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasUser() => $_has(1); @$pb.TagNumber(2) void clearUser() => clearField(2); @$pb.TagNumber(2) User ensureUser() => $_ensure(1); @$pb.TagNumber(3) $core.String get content => $_getSZ(2); @$pb.TagNumber(3) set content($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasContent() => $_has(2); @$pb.TagNumber(3) void clearContent() => clearField(3); @$pb.TagNumber(4) $core.bool get visibleToSende => $_getBF(3); @$pb.TagNumber(4) set visibleToSende($core.bool v) { $_setBool(3, v); } @$pb.TagNumber(4) $core.bool hasVisibleToSende() => $_has(3); @$pb.TagNumber(4) void clearVisibleToSende() => clearField(4); @$pb.TagNumber(7) Image get giftImage => $_getN(4); @$pb.TagNumber(7) set giftImage(Image v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasGiftImage() => $_has(4); @$pb.TagNumber(7) void clearGiftImage() => clearField(7); @$pb.TagNumber(7) Image ensureGiftImage() => $_ensure(4); @$pb.TagNumber(8) $fixnum.Int64 get agreeMsgId => $_getI64(5); @$pb.TagNumber(8) set agreeMsgId($fixnum.Int64 v) { $_setInt64(5, v); } @$pb.TagNumber(8) $core.bool hasAgreeMsgId() => $_has(5); @$pb.TagNumber(8) void clearAgreeMsgId() => clearField(8); @$pb.TagNumber(9) $core.List<$core.String> get colorValueList => $_getList(6); } class MatchAgainstScoreMessage extends $pb.GeneratedMessage { factory MatchAgainstScoreMessage() => create(); MatchAgainstScoreMessage._() : super(); factory MatchAgainstScoreMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory MatchAgainstScoreMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'MatchAgainstScoreMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOM(1, _omitFieldNames ? '' : 'common', subBuilder: Common.create) ..aOM(2, _omitFieldNames ? '' : 'against', subBuilder: Against.create) ..a<$core.int>(3, _omitFieldNames ? '' : 'matchStatus', $pb.PbFieldType.OU3, protoName: 'matchStatus') ..a<$core.int>(4, _omitFieldNames ? '' : 'displayStatus', $pb.PbFieldType.OU3, protoName: 'displayStatus') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') MatchAgainstScoreMessage clone() => MatchAgainstScoreMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') MatchAgainstScoreMessage copyWith(void Function(MatchAgainstScoreMessage) updates) => super.copyWith((message) => updates(message as MatchAgainstScoreMessage)) as MatchAgainstScoreMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static MatchAgainstScoreMessage create() => MatchAgainstScoreMessage._(); MatchAgainstScoreMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static MatchAgainstScoreMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static MatchAgainstScoreMessage? _defaultInstance; @$pb.TagNumber(1) Common get common => $_getN(0); @$pb.TagNumber(1) set common(Common v) { setField(1, v); } @$pb.TagNumber(1) $core.bool hasCommon() => $_has(0); @$pb.TagNumber(1) void clearCommon() => clearField(1); @$pb.TagNumber(1) Common ensureCommon() => $_ensure(0); @$pb.TagNumber(2) Against get against => $_getN(1); @$pb.TagNumber(2) set against(Against v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasAgainst() => $_has(1); @$pb.TagNumber(2) void clearAgainst() => clearField(2); @$pb.TagNumber(2) Against ensureAgainst() => $_ensure(1); @$pb.TagNumber(3) $core.int get matchStatus => $_getIZ(2); @$pb.TagNumber(3) set matchStatus($core.int v) { $_setUnsignedInt32(2, v); } @$pb.TagNumber(3) $core.bool hasMatchStatus() => $_has(2); @$pb.TagNumber(3) void clearMatchStatus() => clearField(3); @$pb.TagNumber(4) $core.int get displayStatus => $_getIZ(3); @$pb.TagNumber(4) set displayStatus($core.int v) { $_setUnsignedInt32(3, v); } @$pb.TagNumber(4) $core.bool hasDisplayStatus() => $_has(3); @$pb.TagNumber(4) void clearDisplayStatus() => clearField(4); } class Against extends $pb.GeneratedMessage { factory Against() => create(); Against._() : super(); factory Against.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Against.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Against', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'leftName', protoName: 'leftName') ..aOM(2, _omitFieldNames ? '' : 'leftLogo', protoName: 'leftLogo', subBuilder: Image.create) ..aOS(3, _omitFieldNames ? '' : 'leftGoal', protoName: 'leftGoal') ..aOS(6, _omitFieldNames ? '' : 'rightName', protoName: 'rightName') ..aOM(7, _omitFieldNames ? '' : 'rightLogo', protoName: 'rightLogo', subBuilder: Image.create) ..aOS(8, _omitFieldNames ? '' : 'rightGoal', protoName: 'rightGoal') ..a<$fixnum.Int64>(11, _omitFieldNames ? '' : 'timestamp', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(12, _omitFieldNames ? '' : 'version', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(13, _omitFieldNames ? '' : 'leftTeamId', $pb.PbFieldType.OU6, protoName: 'leftTeamId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(14, _omitFieldNames ? '' : 'rightTeamId', $pb.PbFieldType.OU6, protoName: 'rightTeamId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(15, _omitFieldNames ? '' : 'diffSei2absSecond', $pb.PbFieldType.OU6, protoName: 'diffSei2absSecond', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$core.int>(16, _omitFieldNames ? '' : 'finalGoalStage', $pb.PbFieldType.OU3, protoName: 'finalGoalStage') ..a<$core.int>(17, _omitFieldNames ? '' : 'currentGoalStage', $pb.PbFieldType.OU3, protoName: 'currentGoalStage') ..a<$core.int>(18, _omitFieldNames ? '' : 'leftScoreAddition', $pb.PbFieldType.OU3, protoName: 'leftScoreAddition') ..a<$core.int>(19, _omitFieldNames ? '' : 'rightScoreAddition', $pb.PbFieldType.OU3, protoName: 'rightScoreAddition') ..a<$fixnum.Int64>(20, _omitFieldNames ? '' : 'leftGoalInt', $pb.PbFieldType.OU6, protoName: 'leftGoalInt', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(21, _omitFieldNames ? '' : 'rightGoalInt', $pb.PbFieldType.OU6, protoName: 'rightGoalInt', defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Against clone() => Against()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Against copyWith(void Function(Against) updates) => super.copyWith((message) => updates(message as Against)) as Against; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Against create() => Against._(); Against createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Against getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Against? _defaultInstance; @$pb.TagNumber(1) $core.String get leftName => $_getSZ(0); @$pb.TagNumber(1) set leftName($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasLeftName() => $_has(0); @$pb.TagNumber(1) void clearLeftName() => clearField(1); @$pb.TagNumber(2) Image get leftLogo => $_getN(1); @$pb.TagNumber(2) set leftLogo(Image v) { setField(2, v); } @$pb.TagNumber(2) $core.bool hasLeftLogo() => $_has(1); @$pb.TagNumber(2) void clearLeftLogo() => clearField(2); @$pb.TagNumber(2) Image ensureLeftLogo() => $_ensure(1); @$pb.TagNumber(3) $core.String get leftGoal => $_getSZ(2); @$pb.TagNumber(3) set leftGoal($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasLeftGoal() => $_has(2); @$pb.TagNumber(3) void clearLeftGoal() => clearField(3); @$pb.TagNumber(6) $core.String get rightName => $_getSZ(3); @$pb.TagNumber(6) set rightName($core.String v) { $_setString(3, v); } @$pb.TagNumber(6) $core.bool hasRightName() => $_has(3); @$pb.TagNumber(6) void clearRightName() => clearField(6); @$pb.TagNumber(7) Image get rightLogo => $_getN(4); @$pb.TagNumber(7) set rightLogo(Image v) { setField(7, v); } @$pb.TagNumber(7) $core.bool hasRightLogo() => $_has(4); @$pb.TagNumber(7) void clearRightLogo() => clearField(7); @$pb.TagNumber(7) Image ensureRightLogo() => $_ensure(4); @$pb.TagNumber(8) $core.String get rightGoal => $_getSZ(5); @$pb.TagNumber(8) set rightGoal($core.String v) { $_setString(5, v); } @$pb.TagNumber(8) $core.bool hasRightGoal() => $_has(5); @$pb.TagNumber(8) void clearRightGoal() => clearField(8); @$pb.TagNumber(11) $fixnum.Int64 get timestamp => $_getI64(6); @$pb.TagNumber(11) set timestamp($fixnum.Int64 v) { $_setInt64(6, v); } @$pb.TagNumber(11) $core.bool hasTimestamp() => $_has(6); @$pb.TagNumber(11) void clearTimestamp() => clearField(11); @$pb.TagNumber(12) $fixnum.Int64 get version => $_getI64(7); @$pb.TagNumber(12) set version($fixnum.Int64 v) { $_setInt64(7, v); } @$pb.TagNumber(12) $core.bool hasVersion() => $_has(7); @$pb.TagNumber(12) void clearVersion() => clearField(12); @$pb.TagNumber(13) $fixnum.Int64 get leftTeamId => $_getI64(8); @$pb.TagNumber(13) set leftTeamId($fixnum.Int64 v) { $_setInt64(8, v); } @$pb.TagNumber(13) $core.bool hasLeftTeamId() => $_has(8); @$pb.TagNumber(13) void clearLeftTeamId() => clearField(13); @$pb.TagNumber(14) $fixnum.Int64 get rightTeamId => $_getI64(9); @$pb.TagNumber(14) set rightTeamId($fixnum.Int64 v) { $_setInt64(9, v); } @$pb.TagNumber(14) $core.bool hasRightTeamId() => $_has(9); @$pb.TagNumber(14) void clearRightTeamId() => clearField(14); @$pb.TagNumber(15) $fixnum.Int64 get diffSei2absSecond => $_getI64(10); @$pb.TagNumber(15) set diffSei2absSecond($fixnum.Int64 v) { $_setInt64(10, v); } @$pb.TagNumber(15) $core.bool hasDiffSei2absSecond() => $_has(10); @$pb.TagNumber(15) void clearDiffSei2absSecond() => clearField(15); @$pb.TagNumber(16) $core.int get finalGoalStage => $_getIZ(11); @$pb.TagNumber(16) set finalGoalStage($core.int v) { $_setUnsignedInt32(11, v); } @$pb.TagNumber(16) $core.bool hasFinalGoalStage() => $_has(11); @$pb.TagNumber(16) void clearFinalGoalStage() => clearField(16); @$pb.TagNumber(17) $core.int get currentGoalStage => $_getIZ(12); @$pb.TagNumber(17) set currentGoalStage($core.int v) { $_setUnsignedInt32(12, v); } @$pb.TagNumber(17) $core.bool hasCurrentGoalStage() => $_has(12); @$pb.TagNumber(17) void clearCurrentGoalStage() => clearField(17); @$pb.TagNumber(18) $core.int get leftScoreAddition => $_getIZ(13); @$pb.TagNumber(18) set leftScoreAddition($core.int v) { $_setUnsignedInt32(13, v); } @$pb.TagNumber(18) $core.bool hasLeftScoreAddition() => $_has(13); @$pb.TagNumber(18) void clearLeftScoreAddition() => clearField(18); @$pb.TagNumber(19) $core.int get rightScoreAddition => $_getIZ(14); @$pb.TagNumber(19) set rightScoreAddition($core.int v) { $_setUnsignedInt32(14, v); } @$pb.TagNumber(19) $core.bool hasRightScoreAddition() => $_has(14); @$pb.TagNumber(19) void clearRightScoreAddition() => clearField(19); @$pb.TagNumber(20) $fixnum.Int64 get leftGoalInt => $_getI64(15); @$pb.TagNumber(20) set leftGoalInt($fixnum.Int64 v) { $_setInt64(15, v); } @$pb.TagNumber(20) $core.bool hasLeftGoalInt() => $_has(15); @$pb.TagNumber(20) void clearLeftGoalInt() => clearField(20); @$pb.TagNumber(21) $fixnum.Int64 get rightGoalInt => $_getI64(16); @$pb.TagNumber(21) set rightGoalInt($fixnum.Int64 v) { $_setInt64(16, v); } @$pb.TagNumber(21) $core.bool hasRightGoalInt() => $_has(16); @$pb.TagNumber(21) void clearRightGoalInt() => clearField(21); } class Common extends $pb.GeneratedMessage { factory Common() => create(); Common._() : super(); factory Common.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Common.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Common', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'method') ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'msgId', $pb.PbFieldType.OU6, protoName: 'msgId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'roomId', $pb.PbFieldType.OU6, protoName: 'roomId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'createTime', $pb.PbFieldType.OU6, protoName: 'createTime', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$core.int>(5, _omitFieldNames ? '' : 'monitor', $pb.PbFieldType.OU3) ..aOB(6, _omitFieldNames ? '' : 'isShowMsg', protoName: 'isShowMsg') ..aOS(7, _omitFieldNames ? '' : 'describe') ..a<$fixnum.Int64>(9, _omitFieldNames ? '' : 'foldType', $pb.PbFieldType.OU6, protoName: 'foldType', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(10, _omitFieldNames ? '' : 'anchorFoldType', $pb.PbFieldType.OU6, protoName: 'anchorFoldType', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(11, _omitFieldNames ? '' : 'priorityScore', $pb.PbFieldType.OU6, protoName: 'priorityScore', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(12, _omitFieldNames ? '' : 'logId', protoName: 'logId') ..aOS(13, _omitFieldNames ? '' : 'msgProcessFilterK', protoName: 'msgProcessFilterK') ..aOS(14, _omitFieldNames ? '' : 'msgProcessFilterV', protoName: 'msgProcessFilterV') ..aOM(15, _omitFieldNames ? '' : 'user', subBuilder: User.create) ..a<$fixnum.Int64>(17, _omitFieldNames ? '' : 'anchorFoldTypeV2', $pb.PbFieldType.OU6, protoName: 'anchorFoldTypeV2', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(18, _omitFieldNames ? '' : 'processAtSeiTimeMs', $pb.PbFieldType.OU6, protoName: 'processAtSeiTimeMs', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(19, _omitFieldNames ? '' : 'randomDispatchMs', $pb.PbFieldType.OU6, protoName: 'randomDispatchMs', defaultOrMaker: $fixnum.Int64.ZERO) ..aOB(20, _omitFieldNames ? '' : 'isDispatch', protoName: 'isDispatch') ..a<$fixnum.Int64>(21, _omitFieldNames ? '' : 'channelId', $pb.PbFieldType.OU6, protoName: 'channelId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(22, _omitFieldNames ? '' : 'diffSei2absSecond', $pb.PbFieldType.OU6, protoName: 'diffSei2absSecond', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(23, _omitFieldNames ? '' : 'anchorFoldDuration', $pb.PbFieldType.OU6, protoName: 'anchorFoldDuration', defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Common clone() => Common()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Common copyWith(void Function(Common) updates) => super.copyWith((message) => updates(message as Common)) as Common; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Common create() => Common._(); Common createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Common getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Common? _defaultInstance; @$pb.TagNumber(1) $core.String get method => $_getSZ(0); @$pb.TagNumber(1) set method($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasMethod() => $_has(0); @$pb.TagNumber(1) void clearMethod() => clearField(1); @$pb.TagNumber(2) $fixnum.Int64 get msgId => $_getI64(1); @$pb.TagNumber(2) set msgId($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasMsgId() => $_has(1); @$pb.TagNumber(2) void clearMsgId() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get roomId => $_getI64(2); @$pb.TagNumber(3) set roomId($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasRoomId() => $_has(2); @$pb.TagNumber(3) void clearRoomId() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get createTime => $_getI64(3); @$pb.TagNumber(4) set createTime($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasCreateTime() => $_has(3); @$pb.TagNumber(4) void clearCreateTime() => clearField(4); @$pb.TagNumber(5) $core.int get monitor => $_getIZ(4); @$pb.TagNumber(5) set monitor($core.int v) { $_setUnsignedInt32(4, v); } @$pb.TagNumber(5) $core.bool hasMonitor() => $_has(4); @$pb.TagNumber(5) void clearMonitor() => clearField(5); @$pb.TagNumber(6) $core.bool get isShowMsg => $_getBF(5); @$pb.TagNumber(6) set isShowMsg($core.bool v) { $_setBool(5, v); } @$pb.TagNumber(6) $core.bool hasIsShowMsg() => $_has(5); @$pb.TagNumber(6) void clearIsShowMsg() => clearField(6); @$pb.TagNumber(7) $core.String get describe => $_getSZ(6); @$pb.TagNumber(7) set describe($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasDescribe() => $_has(6); @$pb.TagNumber(7) void clearDescribe() => clearField(7); @$pb.TagNumber(9) $fixnum.Int64 get foldType => $_getI64(7); @$pb.TagNumber(9) set foldType($fixnum.Int64 v) { $_setInt64(7, v); } @$pb.TagNumber(9) $core.bool hasFoldType() => $_has(7); @$pb.TagNumber(9) void clearFoldType() => clearField(9); @$pb.TagNumber(10) $fixnum.Int64 get anchorFoldType => $_getI64(8); @$pb.TagNumber(10) set anchorFoldType($fixnum.Int64 v) { $_setInt64(8, v); } @$pb.TagNumber(10) $core.bool hasAnchorFoldType() => $_has(8); @$pb.TagNumber(10) void clearAnchorFoldType() => clearField(10); @$pb.TagNumber(11) $fixnum.Int64 get priorityScore => $_getI64(9); @$pb.TagNumber(11) set priorityScore($fixnum.Int64 v) { $_setInt64(9, v); } @$pb.TagNumber(11) $core.bool hasPriorityScore() => $_has(9); @$pb.TagNumber(11) void clearPriorityScore() => clearField(11); @$pb.TagNumber(12) $core.String get logId => $_getSZ(10); @$pb.TagNumber(12) set logId($core.String v) { $_setString(10, v); } @$pb.TagNumber(12) $core.bool hasLogId() => $_has(10); @$pb.TagNumber(12) void clearLogId() => clearField(12); @$pb.TagNumber(13) $core.String get msgProcessFilterK => $_getSZ(11); @$pb.TagNumber(13) set msgProcessFilterK($core.String v) { $_setString(11, v); } @$pb.TagNumber(13) $core.bool hasMsgProcessFilterK() => $_has(11); @$pb.TagNumber(13) void clearMsgProcessFilterK() => clearField(13); @$pb.TagNumber(14) $core.String get msgProcessFilterV => $_getSZ(12); @$pb.TagNumber(14) set msgProcessFilterV($core.String v) { $_setString(12, v); } @$pb.TagNumber(14) $core.bool hasMsgProcessFilterV() => $_has(12); @$pb.TagNumber(14) void clearMsgProcessFilterV() => clearField(14); @$pb.TagNumber(15) User get user => $_getN(13); @$pb.TagNumber(15) set user(User v) { setField(15, v); } @$pb.TagNumber(15) $core.bool hasUser() => $_has(13); @$pb.TagNumber(15) void clearUser() => clearField(15); @$pb.TagNumber(15) User ensureUser() => $_ensure(13); @$pb.TagNumber(17) $fixnum.Int64 get anchorFoldTypeV2 => $_getI64(14); @$pb.TagNumber(17) set anchorFoldTypeV2($fixnum.Int64 v) { $_setInt64(14, v); } @$pb.TagNumber(17) $core.bool hasAnchorFoldTypeV2() => $_has(14); @$pb.TagNumber(17) void clearAnchorFoldTypeV2() => clearField(17); @$pb.TagNumber(18) $fixnum.Int64 get processAtSeiTimeMs => $_getI64(15); @$pb.TagNumber(18) set processAtSeiTimeMs($fixnum.Int64 v) { $_setInt64(15, v); } @$pb.TagNumber(18) $core.bool hasProcessAtSeiTimeMs() => $_has(15); @$pb.TagNumber(18) void clearProcessAtSeiTimeMs() => clearField(18); @$pb.TagNumber(19) $fixnum.Int64 get randomDispatchMs => $_getI64(16); @$pb.TagNumber(19) set randomDispatchMs($fixnum.Int64 v) { $_setInt64(16, v); } @$pb.TagNumber(19) $core.bool hasRandomDispatchMs() => $_has(16); @$pb.TagNumber(19) void clearRandomDispatchMs() => clearField(19); @$pb.TagNumber(20) $core.bool get isDispatch => $_getBF(17); @$pb.TagNumber(20) set isDispatch($core.bool v) { $_setBool(17, v); } @$pb.TagNumber(20) $core.bool hasIsDispatch() => $_has(17); @$pb.TagNumber(20) void clearIsDispatch() => clearField(20); @$pb.TagNumber(21) $fixnum.Int64 get channelId => $_getI64(18); @$pb.TagNumber(21) set channelId($fixnum.Int64 v) { $_setInt64(18, v); } @$pb.TagNumber(21) $core.bool hasChannelId() => $_has(18); @$pb.TagNumber(21) void clearChannelId() => clearField(21); @$pb.TagNumber(22) $fixnum.Int64 get diffSei2absSecond => $_getI64(19); @$pb.TagNumber(22) set diffSei2absSecond($fixnum.Int64 v) { $_setInt64(19, v); } @$pb.TagNumber(22) $core.bool hasDiffSei2absSecond() => $_has(19); @$pb.TagNumber(22) void clearDiffSei2absSecond() => clearField(22); @$pb.TagNumber(23) $fixnum.Int64 get anchorFoldDuration => $_getI64(20); @$pb.TagNumber(23) set anchorFoldDuration($fixnum.Int64 v) { $_setInt64(20, v); } @$pb.TagNumber(23) $core.bool hasAnchorFoldDuration() => $_has(20); @$pb.TagNumber(23) void clearAnchorFoldDuration() => clearField(23); } class User extends $pb.GeneratedMessage { factory User() => create(); User._() : super(); factory User.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory User.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'User', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'shortId', $pb.PbFieldType.OU6, protoName: 'shortId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(3, _omitFieldNames ? '' : 'nickName', protoName: 'nickName') ..a<$core.int>(4, _omitFieldNames ? '' : 'gender', $pb.PbFieldType.OU3) ..aOS(5, _omitFieldNames ? '' : 'Signature', protoName: 'Signature') ..a<$core.int>(6, _omitFieldNames ? '' : 'Level', $pb.PbFieldType.OU3, protoName: 'Level') ..a<$fixnum.Int64>(7, _omitFieldNames ? '' : 'Birthday', $pb.PbFieldType.OU6, protoName: 'Birthday', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(8, _omitFieldNames ? '' : 'Telephone', protoName: 'Telephone') ..aOM(9, _omitFieldNames ? '' : 'AvatarThumb', protoName: 'AvatarThumb', subBuilder: Image.create) ..aOM(10, _omitFieldNames ? '' : 'AvatarMedium', protoName: 'AvatarMedium', subBuilder: Image.create) ..aOM(11, _omitFieldNames ? '' : 'AvatarLarge', protoName: 'AvatarLarge', subBuilder: Image.create) ..aOB(12, _omitFieldNames ? '' : 'Verified', protoName: 'Verified') ..a<$core.int>(13, _omitFieldNames ? '' : 'Experience', $pb.PbFieldType.OU3, protoName: 'Experience') ..aOS(14, _omitFieldNames ? '' : 'city') ..a<$core.int>(15, _omitFieldNames ? '' : 'Status', $pb.PbFieldType.O3, protoName: 'Status') ..a<$fixnum.Int64>(16, _omitFieldNames ? '' : 'CreateTime', $pb.PbFieldType.OU6, protoName: 'CreateTime', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(17, _omitFieldNames ? '' : 'ModifyTime', $pb.PbFieldType.OU6, protoName: 'ModifyTime', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$core.int>(18, _omitFieldNames ? '' : 'Secret', $pb.PbFieldType.OU3, protoName: 'Secret') ..aOS(19, _omitFieldNames ? '' : 'ShareQrcodeUri', protoName: 'ShareQrcodeUri') ..a<$core.int>(20, _omitFieldNames ? '' : 'IncomeSharePercent', $pb.PbFieldType.OU3, protoName: 'IncomeSharePercent') ..pc(21, _omitFieldNames ? '' : 'BadgeImageList', $pb.PbFieldType.PM, protoName: 'BadgeImageList', subBuilder: Image.create) ..aOM(22, _omitFieldNames ? '' : 'FollowInfo', protoName: 'FollowInfo', subBuilder: FollowInfo.create) ..aOS(26, _omitFieldNames ? '' : 'SpecialId', protoName: 'SpecialId') ..aOM(27, _omitFieldNames ? '' : 'AvatarBorder', protoName: 'AvatarBorder', subBuilder: Image.create) ..aOM(28, _omitFieldNames ? '' : 'Medal', protoName: 'Medal', subBuilder: Image.create) ..pc(29, _omitFieldNames ? '' : 'RealTimeIconsList', $pb.PbFieldType.PM, protoName: 'RealTimeIconsList', subBuilder: Image.create) ..aOS(38, _omitFieldNames ? '' : 'displayId', protoName: 'displayId') ..aOS(46, _omitFieldNames ? '' : 'secUid', protoName: 'secUid') ..a<$fixnum.Int64>(1022, _omitFieldNames ? '' : 'fanTicketCount', $pb.PbFieldType.OU6, protoName: 'fanTicketCount', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(1028, _omitFieldNames ? '' : 'idStr', protoName: 'idStr') ..a<$core.int>(1045, _omitFieldNames ? '' : 'ageRange', $pb.PbFieldType.OU3, protoName: 'ageRange') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') User clone() => User()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') User copyWith(void Function(User) updates) => super.copyWith((message) => updates(message as User)) as User; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static User create() => User._(); User createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static User getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static User? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get id => $_getI64(0); @$pb.TagNumber(1) set id($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasId() => $_has(0); @$pb.TagNumber(1) void clearId() => clearField(1); @$pb.TagNumber(2) $fixnum.Int64 get shortId => $_getI64(1); @$pb.TagNumber(2) set shortId($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasShortId() => $_has(1); @$pb.TagNumber(2) void clearShortId() => clearField(2); @$pb.TagNumber(3) $core.String get nickName => $_getSZ(2); @$pb.TagNumber(3) set nickName($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasNickName() => $_has(2); @$pb.TagNumber(3) void clearNickName() => clearField(3); @$pb.TagNumber(4) $core.int get gender => $_getIZ(3); @$pb.TagNumber(4) set gender($core.int v) { $_setUnsignedInt32(3, v); } @$pb.TagNumber(4) $core.bool hasGender() => $_has(3); @$pb.TagNumber(4) void clearGender() => clearField(4); @$pb.TagNumber(5) $core.String get signature => $_getSZ(4); @$pb.TagNumber(5) set signature($core.String v) { $_setString(4, v); } @$pb.TagNumber(5) $core.bool hasSignature() => $_has(4); @$pb.TagNumber(5) void clearSignature() => clearField(5); @$pb.TagNumber(6) $core.int get level => $_getIZ(5); @$pb.TagNumber(6) set level($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasLevel() => $_has(5); @$pb.TagNumber(6) void clearLevel() => clearField(6); @$pb.TagNumber(7) $fixnum.Int64 get birthday => $_getI64(6); @$pb.TagNumber(7) set birthday($fixnum.Int64 v) { $_setInt64(6, v); } @$pb.TagNumber(7) $core.bool hasBirthday() => $_has(6); @$pb.TagNumber(7) void clearBirthday() => clearField(7); @$pb.TagNumber(8) $core.String get telephone => $_getSZ(7); @$pb.TagNumber(8) set telephone($core.String v) { $_setString(7, v); } @$pb.TagNumber(8) $core.bool hasTelephone() => $_has(7); @$pb.TagNumber(8) void clearTelephone() => clearField(8); @$pb.TagNumber(9) Image get avatarThumb => $_getN(8); @$pb.TagNumber(9) set avatarThumb(Image v) { setField(9, v); } @$pb.TagNumber(9) $core.bool hasAvatarThumb() => $_has(8); @$pb.TagNumber(9) void clearAvatarThumb() => clearField(9); @$pb.TagNumber(9) Image ensureAvatarThumb() => $_ensure(8); @$pb.TagNumber(10) Image get avatarMedium => $_getN(9); @$pb.TagNumber(10) set avatarMedium(Image v) { setField(10, v); } @$pb.TagNumber(10) $core.bool hasAvatarMedium() => $_has(9); @$pb.TagNumber(10) void clearAvatarMedium() => clearField(10); @$pb.TagNumber(10) Image ensureAvatarMedium() => $_ensure(9); @$pb.TagNumber(11) Image get avatarLarge => $_getN(10); @$pb.TagNumber(11) set avatarLarge(Image v) { setField(11, v); } @$pb.TagNumber(11) $core.bool hasAvatarLarge() => $_has(10); @$pb.TagNumber(11) void clearAvatarLarge() => clearField(11); @$pb.TagNumber(11) Image ensureAvatarLarge() => $_ensure(10); @$pb.TagNumber(12) $core.bool get verified => $_getBF(11); @$pb.TagNumber(12) set verified($core.bool v) { $_setBool(11, v); } @$pb.TagNumber(12) $core.bool hasVerified() => $_has(11); @$pb.TagNumber(12) void clearVerified() => clearField(12); @$pb.TagNumber(13) $core.int get experience => $_getIZ(12); @$pb.TagNumber(13) set experience($core.int v) { $_setUnsignedInt32(12, v); } @$pb.TagNumber(13) $core.bool hasExperience() => $_has(12); @$pb.TagNumber(13) void clearExperience() => clearField(13); @$pb.TagNumber(14) $core.String get city => $_getSZ(13); @$pb.TagNumber(14) set city($core.String v) { $_setString(13, v); } @$pb.TagNumber(14) $core.bool hasCity() => $_has(13); @$pb.TagNumber(14) void clearCity() => clearField(14); @$pb.TagNumber(15) $core.int get status => $_getIZ(14); @$pb.TagNumber(15) set status($core.int v) { $_setSignedInt32(14, v); } @$pb.TagNumber(15) $core.bool hasStatus() => $_has(14); @$pb.TagNumber(15) void clearStatus() => clearField(15); @$pb.TagNumber(16) $fixnum.Int64 get createTime => $_getI64(15); @$pb.TagNumber(16) set createTime($fixnum.Int64 v) { $_setInt64(15, v); } @$pb.TagNumber(16) $core.bool hasCreateTime() => $_has(15); @$pb.TagNumber(16) void clearCreateTime() => clearField(16); @$pb.TagNumber(17) $fixnum.Int64 get modifyTime => $_getI64(16); @$pb.TagNumber(17) set modifyTime($fixnum.Int64 v) { $_setInt64(16, v); } @$pb.TagNumber(17) $core.bool hasModifyTime() => $_has(16); @$pb.TagNumber(17) void clearModifyTime() => clearField(17); @$pb.TagNumber(18) $core.int get secret => $_getIZ(17); @$pb.TagNumber(18) set secret($core.int v) { $_setUnsignedInt32(17, v); } @$pb.TagNumber(18) $core.bool hasSecret() => $_has(17); @$pb.TagNumber(18) void clearSecret() => clearField(18); @$pb.TagNumber(19) $core.String get shareQrcodeUri => $_getSZ(18); @$pb.TagNumber(19) set shareQrcodeUri($core.String v) { $_setString(18, v); } @$pb.TagNumber(19) $core.bool hasShareQrcodeUri() => $_has(18); @$pb.TagNumber(19) void clearShareQrcodeUri() => clearField(19); @$pb.TagNumber(20) $core.int get incomeSharePercent => $_getIZ(19); @$pb.TagNumber(20) set incomeSharePercent($core.int v) { $_setUnsignedInt32(19, v); } @$pb.TagNumber(20) $core.bool hasIncomeSharePercent() => $_has(19); @$pb.TagNumber(20) void clearIncomeSharePercent() => clearField(20); @$pb.TagNumber(21) $core.List get badgeImageList => $_getList(20); @$pb.TagNumber(22) FollowInfo get followInfo => $_getN(21); @$pb.TagNumber(22) set followInfo(FollowInfo v) { setField(22, v); } @$pb.TagNumber(22) $core.bool hasFollowInfo() => $_has(21); @$pb.TagNumber(22) void clearFollowInfo() => clearField(22); @$pb.TagNumber(22) FollowInfo ensureFollowInfo() => $_ensure(21); @$pb.TagNumber(26) $core.String get specialId => $_getSZ(22); @$pb.TagNumber(26) set specialId($core.String v) { $_setString(22, v); } @$pb.TagNumber(26) $core.bool hasSpecialId() => $_has(22); @$pb.TagNumber(26) void clearSpecialId() => clearField(26); @$pb.TagNumber(27) Image get avatarBorder => $_getN(23); @$pb.TagNumber(27) set avatarBorder(Image v) { setField(27, v); } @$pb.TagNumber(27) $core.bool hasAvatarBorder() => $_has(23); @$pb.TagNumber(27) void clearAvatarBorder() => clearField(27); @$pb.TagNumber(27) Image ensureAvatarBorder() => $_ensure(23); @$pb.TagNumber(28) Image get medal => $_getN(24); @$pb.TagNumber(28) set medal(Image v) { setField(28, v); } @$pb.TagNumber(28) $core.bool hasMedal() => $_has(24); @$pb.TagNumber(28) void clearMedal() => clearField(28); @$pb.TagNumber(28) Image ensureMedal() => $_ensure(24); @$pb.TagNumber(29) $core.List get realTimeIconsList => $_getList(25); @$pb.TagNumber(38) $core.String get displayId => $_getSZ(26); @$pb.TagNumber(38) set displayId($core.String v) { $_setString(26, v); } @$pb.TagNumber(38) $core.bool hasDisplayId() => $_has(26); @$pb.TagNumber(38) void clearDisplayId() => clearField(38); @$pb.TagNumber(46) $core.String get secUid => $_getSZ(27); @$pb.TagNumber(46) set secUid($core.String v) { $_setString(27, v); } @$pb.TagNumber(46) $core.bool hasSecUid() => $_has(27); @$pb.TagNumber(46) void clearSecUid() => clearField(46); @$pb.TagNumber(1022) $fixnum.Int64 get fanTicketCount => $_getI64(28); @$pb.TagNumber(1022) set fanTicketCount($fixnum.Int64 v) { $_setInt64(28, v); } @$pb.TagNumber(1022) $core.bool hasFanTicketCount() => $_has(28); @$pb.TagNumber(1022) void clearFanTicketCount() => clearField(1022); @$pb.TagNumber(1028) $core.String get idStr => $_getSZ(29); @$pb.TagNumber(1028) set idStr($core.String v) { $_setString(29, v); } @$pb.TagNumber(1028) $core.bool hasIdStr() => $_has(29); @$pb.TagNumber(1028) void clearIdStr() => clearField(1028); @$pb.TagNumber(1045) $core.int get ageRange => $_getIZ(30); @$pb.TagNumber(1045) set ageRange($core.int v) { $_setUnsignedInt32(30, v); } @$pb.TagNumber(1045) $core.bool hasAgeRange() => $_has(30); @$pb.TagNumber(1045) void clearAgeRange() => clearField(1045); } class FollowInfo extends $pb.GeneratedMessage { factory FollowInfo() => create(); FollowInfo._() : super(); factory FollowInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory FollowInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'FollowInfo', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'followingCount', $pb.PbFieldType.OU6, protoName: 'followingCount', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'followerCount', $pb.PbFieldType.OU6, protoName: 'followerCount', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'followStatus', $pb.PbFieldType.OU6, protoName: 'followStatus', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'pushStatus', $pb.PbFieldType.OU6, protoName: 'pushStatus', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(5, _omitFieldNames ? '' : 'remarkName', protoName: 'remarkName') ..aOS(6, _omitFieldNames ? '' : 'followerCountStr', protoName: 'followerCountStr') ..aOS(7, _omitFieldNames ? '' : 'followingCountStr', protoName: 'followingCountStr') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') FollowInfo clone() => FollowInfo()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') FollowInfo copyWith(void Function(FollowInfo) updates) => super.copyWith((message) => updates(message as FollowInfo)) as FollowInfo; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static FollowInfo create() => FollowInfo._(); FollowInfo createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static FollowInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static FollowInfo? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get followingCount => $_getI64(0); @$pb.TagNumber(1) set followingCount($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasFollowingCount() => $_has(0); @$pb.TagNumber(1) void clearFollowingCount() => clearField(1); @$pb.TagNumber(2) $fixnum.Int64 get followerCount => $_getI64(1); @$pb.TagNumber(2) set followerCount($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasFollowerCount() => $_has(1); @$pb.TagNumber(2) void clearFollowerCount() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get followStatus => $_getI64(2); @$pb.TagNumber(3) set followStatus($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasFollowStatus() => $_has(2); @$pb.TagNumber(3) void clearFollowStatus() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get pushStatus => $_getI64(3); @$pb.TagNumber(4) set pushStatus($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasPushStatus() => $_has(3); @$pb.TagNumber(4) void clearPushStatus() => clearField(4); @$pb.TagNumber(5) $core.String get remarkName => $_getSZ(4); @$pb.TagNumber(5) set remarkName($core.String v) { $_setString(4, v); } @$pb.TagNumber(5) $core.bool hasRemarkName() => $_has(4); @$pb.TagNumber(5) void clearRemarkName() => clearField(5); @$pb.TagNumber(6) $core.String get followerCountStr => $_getSZ(5); @$pb.TagNumber(6) set followerCountStr($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) $core.bool hasFollowerCountStr() => $_has(5); @$pb.TagNumber(6) void clearFollowerCountStr() => clearField(6); @$pb.TagNumber(7) $core.String get followingCountStr => $_getSZ(6); @$pb.TagNumber(7) set followingCountStr($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasFollowingCountStr() => $_has(6); @$pb.TagNumber(7) void clearFollowingCountStr() => clearField(7); } class Image extends $pb.GeneratedMessage { factory Image() => create(); Image._() : super(); factory Image.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Image.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Image', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..pPS(1, _omitFieldNames ? '' : 'urlListList', protoName: 'urlListList') ..aOS(2, _omitFieldNames ? '' : 'uri') ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'height', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'width', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(5, _omitFieldNames ? '' : 'avgColor', protoName: 'avgColor') ..a<$core.int>(6, _omitFieldNames ? '' : 'imageType', $pb.PbFieldType.OU3, protoName: 'imageType') ..aOS(7, _omitFieldNames ? '' : 'openWebUrl', protoName: 'openWebUrl') ..aOM(8, _omitFieldNames ? '' : 'content', subBuilder: ImageContent.create) ..aOB(9, _omitFieldNames ? '' : 'isAnimated', protoName: 'isAnimated') ..aOM(10, _omitFieldNames ? '' : 'FlexSettingList', protoName: 'FlexSettingList', subBuilder: NinePatchSetting.create) ..aOM(11, _omitFieldNames ? '' : 'TextSettingList', protoName: 'TextSettingList', subBuilder: NinePatchSetting.create) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Image clone() => Image()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Image copyWith(void Function(Image) updates) => super.copyWith((message) => updates(message as Image)) as Image; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Image create() => Image._(); Image createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Image getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Image? _defaultInstance; @$pb.TagNumber(1) $core.List<$core.String> get urlListList => $_getList(0); @$pb.TagNumber(2) $core.String get uri => $_getSZ(1); @$pb.TagNumber(2) set uri($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasUri() => $_has(1); @$pb.TagNumber(2) void clearUri() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get height => $_getI64(2); @$pb.TagNumber(3) set height($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasHeight() => $_has(2); @$pb.TagNumber(3) void clearHeight() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get width => $_getI64(3); @$pb.TagNumber(4) set width($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasWidth() => $_has(3); @$pb.TagNumber(4) void clearWidth() => clearField(4); @$pb.TagNumber(5) $core.String get avgColor => $_getSZ(4); @$pb.TagNumber(5) set avgColor($core.String v) { $_setString(4, v); } @$pb.TagNumber(5) $core.bool hasAvgColor() => $_has(4); @$pb.TagNumber(5) void clearAvgColor() => clearField(5); @$pb.TagNumber(6) $core.int get imageType => $_getIZ(5); @$pb.TagNumber(6) set imageType($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasImageType() => $_has(5); @$pb.TagNumber(6) void clearImageType() => clearField(6); @$pb.TagNumber(7) $core.String get openWebUrl => $_getSZ(6); @$pb.TagNumber(7) set openWebUrl($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasOpenWebUrl() => $_has(6); @$pb.TagNumber(7) void clearOpenWebUrl() => clearField(7); @$pb.TagNumber(8) ImageContent get content => $_getN(7); @$pb.TagNumber(8) set content(ImageContent v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasContent() => $_has(7); @$pb.TagNumber(8) void clearContent() => clearField(8); @$pb.TagNumber(8) ImageContent ensureContent() => $_ensure(7); @$pb.TagNumber(9) $core.bool get isAnimated => $_getBF(8); @$pb.TagNumber(9) set isAnimated($core.bool v) { $_setBool(8, v); } @$pb.TagNumber(9) $core.bool hasIsAnimated() => $_has(8); @$pb.TagNumber(9) void clearIsAnimated() => clearField(9); @$pb.TagNumber(10) NinePatchSetting get flexSettingList => $_getN(9); @$pb.TagNumber(10) set flexSettingList(NinePatchSetting v) { setField(10, v); } @$pb.TagNumber(10) $core.bool hasFlexSettingList() => $_has(9); @$pb.TagNumber(10) void clearFlexSettingList() => clearField(10); @$pb.TagNumber(10) NinePatchSetting ensureFlexSettingList() => $_ensure(9); @$pb.TagNumber(11) NinePatchSetting get textSettingList => $_getN(10); @$pb.TagNumber(11) set textSettingList(NinePatchSetting v) { setField(11, v); } @$pb.TagNumber(11) $core.bool hasTextSettingList() => $_has(10); @$pb.TagNumber(11) void clearTextSettingList() => clearField(11); @$pb.TagNumber(11) NinePatchSetting ensureTextSettingList() => $_ensure(10); } class NinePatchSetting extends $pb.GeneratedMessage { factory NinePatchSetting() => create(); NinePatchSetting._() : super(); factory NinePatchSetting.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory NinePatchSetting.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'NinePatchSetting', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..pPS(1, _omitFieldNames ? '' : 'settingListList', protoName: 'settingListList') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') NinePatchSetting clone() => NinePatchSetting()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') NinePatchSetting copyWith(void Function(NinePatchSetting) updates) => super.copyWith((message) => updates(message as NinePatchSetting)) as NinePatchSetting; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static NinePatchSetting create() => NinePatchSetting._(); NinePatchSetting createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static NinePatchSetting getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static NinePatchSetting? _defaultInstance; @$pb.TagNumber(1) $core.List<$core.String> get settingListList => $_getList(0); } class ImageContent extends $pb.GeneratedMessage { factory ImageContent() => create(); ImageContent._() : super(); factory ImageContent.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory ImageContent.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ImageContent', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'name') ..aOS(2, _omitFieldNames ? '' : 'fontColor', protoName: 'fontColor') ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'level', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(4, _omitFieldNames ? '' : 'alternativeText', protoName: 'alternativeText') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') ImageContent clone() => ImageContent()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') ImageContent copyWith(void Function(ImageContent) updates) => super.copyWith((message) => updates(message as ImageContent)) as ImageContent; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ImageContent create() => ImageContent._(); ImageContent createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static ImageContent getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static ImageContent? _defaultInstance; @$pb.TagNumber(1) $core.String get name => $_getSZ(0); @$pb.TagNumber(1) set name($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasName() => $_has(0); @$pb.TagNumber(1) void clearName() => clearField(1); @$pb.TagNumber(2) $core.String get fontColor => $_getSZ(1); @$pb.TagNumber(2) set fontColor($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasFontColor() => $_has(1); @$pb.TagNumber(2) void clearFontColor() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get level => $_getI64(2); @$pb.TagNumber(3) set level($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasLevel() => $_has(2); @$pb.TagNumber(3) void clearLevel() => clearField(3); @$pb.TagNumber(4) $core.String get alternativeText => $_getSZ(3); @$pb.TagNumber(4) set alternativeText($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasAlternativeText() => $_has(3); @$pb.TagNumber(4) void clearAlternativeText() => clearField(4); } class PushFrame extends $pb.GeneratedMessage { factory PushFrame() => create(); PushFrame._() : super(); factory PushFrame.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory PushFrame.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PushFrame', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'seqId', $pb.PbFieldType.OU6, protoName: 'seqId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'logId', $pb.PbFieldType.OU6, protoName: 'logId', defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'service', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(4, _omitFieldNames ? '' : 'method', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..pc(5, _omitFieldNames ? '' : 'headersList', $pb.PbFieldType.PM, protoName: 'headersList', subBuilder: HeadersList.create) ..aOS(6, _omitFieldNames ? '' : 'payloadEncoding', protoName: 'payloadEncoding') ..aOS(7, _omitFieldNames ? '' : 'payloadType', protoName: 'payloadType') ..a<$core.List<$core.int>>(8, _omitFieldNames ? '' : 'payload', $pb.PbFieldType.OY) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') PushFrame clone() => PushFrame()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') PushFrame copyWith(void Function(PushFrame) updates) => super.copyWith((message) => updates(message as PushFrame)) as PushFrame; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PushFrame create() => PushFrame._(); PushFrame createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static PushFrame getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static PushFrame? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get seqId => $_getI64(0); @$pb.TagNumber(1) set seqId($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasSeqId() => $_has(0); @$pb.TagNumber(1) void clearSeqId() => clearField(1); @$pb.TagNumber(2) $fixnum.Int64 get logId => $_getI64(1); @$pb.TagNumber(2) set logId($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(2) $core.bool hasLogId() => $_has(1); @$pb.TagNumber(2) void clearLogId() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get service => $_getI64(2); @$pb.TagNumber(3) set service($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasService() => $_has(2); @$pb.TagNumber(3) void clearService() => clearField(3); @$pb.TagNumber(4) $fixnum.Int64 get method => $_getI64(3); @$pb.TagNumber(4) set method($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(4) $core.bool hasMethod() => $_has(3); @$pb.TagNumber(4) void clearMethod() => clearField(4); @$pb.TagNumber(5) $core.List get headersList => $_getList(4); @$pb.TagNumber(6) $core.String get payloadEncoding => $_getSZ(5); @$pb.TagNumber(6) set payloadEncoding($core.String v) { $_setString(5, v); } @$pb.TagNumber(6) $core.bool hasPayloadEncoding() => $_has(5); @$pb.TagNumber(6) void clearPayloadEncoding() => clearField(6); @$pb.TagNumber(7) $core.String get payloadType => $_getSZ(6); @$pb.TagNumber(7) set payloadType($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasPayloadType() => $_has(6); @$pb.TagNumber(7) void clearPayloadType() => clearField(7); @$pb.TagNumber(8) $core.List<$core.int> get payload => $_getN(7); @$pb.TagNumber(8) set payload($core.List<$core.int> v) { $_setBytes(7, v); } @$pb.TagNumber(8) $core.bool hasPayload() => $_has(7); @$pb.TagNumber(8) void clearPayload() => clearField(8); } class kk extends $pb.GeneratedMessage { factory kk() => create(); kk._() : super(); factory kk.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory kk.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'kk', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$core.int>(14, _omitFieldNames ? '' : 'k', $pb.PbFieldType.OU3) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') kk clone() => kk()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') kk copyWith(void Function(kk) updates) => super.copyWith((message) => updates(message as kk)) as kk; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static kk create() => kk._(); kk createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static kk getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static kk? _defaultInstance; @$pb.TagNumber(14) $core.int get k => $_getIZ(0); @$pb.TagNumber(14) set k($core.int v) { $_setUnsignedInt32(0, v); } @$pb.TagNumber(14) $core.bool hasK() => $_has(0); @$pb.TagNumber(14) void clearK() => clearField(14); } class SendMessageBody extends $pb.GeneratedMessage { factory SendMessageBody() => create(); SendMessageBody._() : super(); factory SendMessageBody.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory SendMessageBody.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'SendMessageBody', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'conversationId', protoName: 'conversationId') ..a<$core.int>(2, _omitFieldNames ? '' : 'conversationType', $pb.PbFieldType.OU3, protoName: 'conversationType') ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'conversationShortId', $pb.PbFieldType.OU6, protoName: 'conversationShortId', defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(4, _omitFieldNames ? '' : 'content') ..pc(5, _omitFieldNames ? '' : 'ext', $pb.PbFieldType.PM, subBuilder: ExtList.create) ..a<$core.int>(6, _omitFieldNames ? '' : 'messageType', $pb.PbFieldType.OU3, protoName: 'messageType') ..aOS(7, _omitFieldNames ? '' : 'ticket') ..aOS(8, _omitFieldNames ? '' : 'clientMessageId', protoName: 'clientMessageId') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') SendMessageBody clone() => SendMessageBody()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') SendMessageBody copyWith(void Function(SendMessageBody) updates) => super.copyWith((message) => updates(message as SendMessageBody)) as SendMessageBody; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static SendMessageBody create() => SendMessageBody._(); SendMessageBody createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static SendMessageBody getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static SendMessageBody? _defaultInstance; @$pb.TagNumber(1) $core.String get conversationId => $_getSZ(0); @$pb.TagNumber(1) set conversationId($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasConversationId() => $_has(0); @$pb.TagNumber(1) void clearConversationId() => clearField(1); @$pb.TagNumber(2) $core.int get conversationType => $_getIZ(1); @$pb.TagNumber(2) set conversationType($core.int v) { $_setUnsignedInt32(1, v); } @$pb.TagNumber(2) $core.bool hasConversationType() => $_has(1); @$pb.TagNumber(2) void clearConversationType() => clearField(2); @$pb.TagNumber(3) $fixnum.Int64 get conversationShortId => $_getI64(2); @$pb.TagNumber(3) set conversationShortId($fixnum.Int64 v) { $_setInt64(2, v); } @$pb.TagNumber(3) $core.bool hasConversationShortId() => $_has(2); @$pb.TagNumber(3) void clearConversationShortId() => clearField(3); @$pb.TagNumber(4) $core.String get content => $_getSZ(3); @$pb.TagNumber(4) set content($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasContent() => $_has(3); @$pb.TagNumber(4) void clearContent() => clearField(4); @$pb.TagNumber(5) $core.List get ext => $_getList(4); @$pb.TagNumber(6) $core.int get messageType => $_getIZ(5); @$pb.TagNumber(6) set messageType($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasMessageType() => $_has(5); @$pb.TagNumber(6) void clearMessageType() => clearField(6); @$pb.TagNumber(7) $core.String get ticket => $_getSZ(6); @$pb.TagNumber(7) set ticket($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasTicket() => $_has(6); @$pb.TagNumber(7) void clearTicket() => clearField(7); @$pb.TagNumber(8) $core.String get clientMessageId => $_getSZ(7); @$pb.TagNumber(8) set clientMessageId($core.String v) { $_setString(7, v); } @$pb.TagNumber(8) $core.bool hasClientMessageId() => $_has(7); @$pb.TagNumber(8) void clearClientMessageId() => clearField(8); } class ExtList extends $pb.GeneratedMessage { factory ExtList() => create(); ExtList._() : super(); factory ExtList.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory ExtList.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ExtList', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'key') ..aOS(2, _omitFieldNames ? '' : 'value') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') ExtList clone() => ExtList()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') ExtList copyWith(void Function(ExtList) updates) => super.copyWith((message) => updates(message as ExtList)) as ExtList; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static ExtList create() => ExtList._(); ExtList createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static ExtList getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static ExtList? _defaultInstance; @$pb.TagNumber(1) $core.String get key => $_getSZ(0); @$pb.TagNumber(1) set key($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasKey() => $_has(0); @$pb.TagNumber(1) void clearKey() => clearField(1); @$pb.TagNumber(2) $core.String get value => $_getSZ(1); @$pb.TagNumber(2) set value($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasValue() => $_has(1); @$pb.TagNumber(2) void clearValue() => clearField(2); } class Rsp_F extends $pb.GeneratedMessage { factory Rsp_F() => create(); Rsp_F._() : super(); factory Rsp_F.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Rsp_F.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Rsp.F', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'q1', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'q3', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..aOS(4, _omitFieldNames ? '' : 'q4') ..a<$fixnum.Int64>(5, _omitFieldNames ? '' : 'q5', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Rsp_F clone() => Rsp_F()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Rsp_F copyWith(void Function(Rsp_F) updates) => super.copyWith((message) => updates(message as Rsp_F)) as Rsp_F; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Rsp_F create() => Rsp_F._(); Rsp_F createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Rsp_F getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Rsp_F? _defaultInstance; @$pb.TagNumber(1) $fixnum.Int64 get q1 => $_getI64(0); @$pb.TagNumber(1) set q1($fixnum.Int64 v) { $_setInt64(0, v); } @$pb.TagNumber(1) $core.bool hasQ1() => $_has(0); @$pb.TagNumber(1) void clearQ1() => clearField(1); @$pb.TagNumber(3) $fixnum.Int64 get q3 => $_getI64(1); @$pb.TagNumber(3) set q3($fixnum.Int64 v) { $_setInt64(1, v); } @$pb.TagNumber(3) $core.bool hasQ3() => $_has(1); @$pb.TagNumber(3) void clearQ3() => clearField(3); @$pb.TagNumber(4) $core.String get q4 => $_getSZ(2); @$pb.TagNumber(4) set q4($core.String v) { $_setString(2, v); } @$pb.TagNumber(4) $core.bool hasQ4() => $_has(2); @$pb.TagNumber(4) void clearQ4() => clearField(4); @$pb.TagNumber(5) $fixnum.Int64 get q5 => $_getI64(3); @$pb.TagNumber(5) set q5($fixnum.Int64 v) { $_setInt64(3, v); } @$pb.TagNumber(5) $core.bool hasQ5() => $_has(3); @$pb.TagNumber(5) void clearQ5() => clearField(5); } class Rsp extends $pb.GeneratedMessage { factory Rsp() => create(); Rsp._() : super(); factory Rsp.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory Rsp.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Rsp', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$core.int>(1, _omitFieldNames ? '' : 'a', $pb.PbFieldType.O3) ..a<$core.int>(2, _omitFieldNames ? '' : 'b', $pb.PbFieldType.O3) ..a<$core.int>(3, _omitFieldNames ? '' : 'c', $pb.PbFieldType.O3) ..aOS(4, _omitFieldNames ? '' : 'd') ..a<$core.int>(5, _omitFieldNames ? '' : 'e', $pb.PbFieldType.O3) ..aOM(6, _omitFieldNames ? '' : 'f', subBuilder: Rsp_F.create) ..aOS(7, _omitFieldNames ? '' : 'g') ..a<$fixnum.Int64>(10, _omitFieldNames ? '' : 'h', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(11, _omitFieldNames ? '' : 'i', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..a<$fixnum.Int64>(13, _omitFieldNames ? '' : 'j', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO) ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') Rsp clone() => Rsp()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') Rsp copyWith(void Function(Rsp) updates) => super.copyWith((message) => updates(message as Rsp)) as Rsp; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static Rsp create() => Rsp._(); Rsp createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static Rsp getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static Rsp? _defaultInstance; @$pb.TagNumber(1) $core.int get a => $_getIZ(0); @$pb.TagNumber(1) set a($core.int v) { $_setSignedInt32(0, v); } @$pb.TagNumber(1) $core.bool hasA() => $_has(0); @$pb.TagNumber(1) void clearA() => clearField(1); @$pb.TagNumber(2) $core.int get b => $_getIZ(1); @$pb.TagNumber(2) set b($core.int v) { $_setSignedInt32(1, v); } @$pb.TagNumber(2) $core.bool hasB() => $_has(1); @$pb.TagNumber(2) void clearB() => clearField(2); @$pb.TagNumber(3) $core.int get c => $_getIZ(2); @$pb.TagNumber(3) set c($core.int v) { $_setSignedInt32(2, v); } @$pb.TagNumber(3) $core.bool hasC() => $_has(2); @$pb.TagNumber(3) void clearC() => clearField(3); @$pb.TagNumber(4) $core.String get d => $_getSZ(3); @$pb.TagNumber(4) set d($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasD() => $_has(3); @$pb.TagNumber(4) void clearD() => clearField(4); @$pb.TagNumber(5) $core.int get e => $_getIZ(4); @$pb.TagNumber(5) set e($core.int v) { $_setSignedInt32(4, v); } @$pb.TagNumber(5) $core.bool hasE() => $_has(4); @$pb.TagNumber(5) void clearE() => clearField(5); @$pb.TagNumber(6) Rsp_F get f => $_getN(5); @$pb.TagNumber(6) set f(Rsp_F v) { setField(6, v); } @$pb.TagNumber(6) $core.bool hasF() => $_has(5); @$pb.TagNumber(6) void clearF() => clearField(6); @$pb.TagNumber(6) Rsp_F ensureF() => $_ensure(5); @$pb.TagNumber(7) $core.String get g => $_getSZ(6); @$pb.TagNumber(7) set g($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasG() => $_has(6); @$pb.TagNumber(7) void clearG() => clearField(7); @$pb.TagNumber(10) $fixnum.Int64 get h => $_getI64(7); @$pb.TagNumber(10) set h($fixnum.Int64 v) { $_setInt64(7, v); } @$pb.TagNumber(10) $core.bool hasH() => $_has(7); @$pb.TagNumber(10) void clearH() => clearField(10); @$pb.TagNumber(11) $fixnum.Int64 get i => $_getI64(8); @$pb.TagNumber(11) set i($fixnum.Int64 v) { $_setInt64(8, v); } @$pb.TagNumber(11) $core.bool hasI() => $_has(8); @$pb.TagNumber(11) void clearI() => clearField(11); @$pb.TagNumber(13) $fixnum.Int64 get j => $_getI64(9); @$pb.TagNumber(13) set j($fixnum.Int64 v) { $_setInt64(9, v); } @$pb.TagNumber(13) $core.bool hasJ() => $_has(9); @$pb.TagNumber(13) void clearJ() => clearField(13); } class PreMessage extends $pb.GeneratedMessage { factory PreMessage() => create(); PreMessage._() : super(); factory PreMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory PreMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'PreMessage', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..a<$core.int>(1, _omitFieldNames ? '' : 'cmd', $pb.PbFieldType.OU3) ..a<$core.int>(2, _omitFieldNames ? '' : 'sequenceId', $pb.PbFieldType.OU3, protoName: 'sequenceId') ..aOS(3, _omitFieldNames ? '' : 'sdkVersion', protoName: 'sdkVersion') ..aOS(4, _omitFieldNames ? '' : 'token') ..a<$core.int>(5, _omitFieldNames ? '' : 'refer', $pb.PbFieldType.OU3) ..a<$core.int>(6, _omitFieldNames ? '' : 'inboxType', $pb.PbFieldType.OU3, protoName: 'inboxType') ..aOS(7, _omitFieldNames ? '' : 'buildNumber', protoName: 'buildNumber') ..aOM(8, _omitFieldNames ? '' : 'sendMessageBody', protoName: 'sendMessageBody', subBuilder: SendMessageBody.create) ..aOS(9, _omitFieldNames ? '' : 'aa') ..aOS(11, _omitFieldNames ? '' : 'devicePlatform', protoName: 'devicePlatform') ..pc(15, _omitFieldNames ? '' : 'headers', $pb.PbFieldType.PM, subBuilder: HeadersList.create) ..a<$core.int>(18, _omitFieldNames ? '' : 'authType', $pb.PbFieldType.OU3, protoName: 'authType') ..aOS(21, _omitFieldNames ? '' : 'biz') ..aOS(22, _omitFieldNames ? '' : 'access') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') PreMessage clone() => PreMessage()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') PreMessage copyWith(void Function(PreMessage) updates) => super.copyWith((message) => updates(message as PreMessage)) as PreMessage; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static PreMessage create() => PreMessage._(); PreMessage createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static PreMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static PreMessage? _defaultInstance; @$pb.TagNumber(1) $core.int get cmd => $_getIZ(0); @$pb.TagNumber(1) set cmd($core.int v) { $_setUnsignedInt32(0, v); } @$pb.TagNumber(1) $core.bool hasCmd() => $_has(0); @$pb.TagNumber(1) void clearCmd() => clearField(1); @$pb.TagNumber(2) $core.int get sequenceId => $_getIZ(1); @$pb.TagNumber(2) set sequenceId($core.int v) { $_setUnsignedInt32(1, v); } @$pb.TagNumber(2) $core.bool hasSequenceId() => $_has(1); @$pb.TagNumber(2) void clearSequenceId() => clearField(2); @$pb.TagNumber(3) $core.String get sdkVersion => $_getSZ(2); @$pb.TagNumber(3) set sdkVersion($core.String v) { $_setString(2, v); } @$pb.TagNumber(3) $core.bool hasSdkVersion() => $_has(2); @$pb.TagNumber(3) void clearSdkVersion() => clearField(3); @$pb.TagNumber(4) $core.String get token => $_getSZ(3); @$pb.TagNumber(4) set token($core.String v) { $_setString(3, v); } @$pb.TagNumber(4) $core.bool hasToken() => $_has(3); @$pb.TagNumber(4) void clearToken() => clearField(4); @$pb.TagNumber(5) $core.int get refer => $_getIZ(4); @$pb.TagNumber(5) set refer($core.int v) { $_setUnsignedInt32(4, v); } @$pb.TagNumber(5) $core.bool hasRefer() => $_has(4); @$pb.TagNumber(5) void clearRefer() => clearField(5); @$pb.TagNumber(6) $core.int get inboxType => $_getIZ(5); @$pb.TagNumber(6) set inboxType($core.int v) { $_setUnsignedInt32(5, v); } @$pb.TagNumber(6) $core.bool hasInboxType() => $_has(5); @$pb.TagNumber(6) void clearInboxType() => clearField(6); @$pb.TagNumber(7) $core.String get buildNumber => $_getSZ(6); @$pb.TagNumber(7) set buildNumber($core.String v) { $_setString(6, v); } @$pb.TagNumber(7) $core.bool hasBuildNumber() => $_has(6); @$pb.TagNumber(7) void clearBuildNumber() => clearField(7); @$pb.TagNumber(8) SendMessageBody get sendMessageBody => $_getN(7); @$pb.TagNumber(8) set sendMessageBody(SendMessageBody v) { setField(8, v); } @$pb.TagNumber(8) $core.bool hasSendMessageBody() => $_has(7); @$pb.TagNumber(8) void clearSendMessageBody() => clearField(8); @$pb.TagNumber(8) SendMessageBody ensureSendMessageBody() => $_ensure(7); @$pb.TagNumber(9) $core.String get aa => $_getSZ(8); @$pb.TagNumber(9) set aa($core.String v) { $_setString(8, v); } @$pb.TagNumber(9) $core.bool hasAa() => $_has(8); @$pb.TagNumber(9) void clearAa() => clearField(9); @$pb.TagNumber(11) $core.String get devicePlatform => $_getSZ(9); @$pb.TagNumber(11) set devicePlatform($core.String v) { $_setString(9, v); } @$pb.TagNumber(11) $core.bool hasDevicePlatform() => $_has(9); @$pb.TagNumber(11) void clearDevicePlatform() => clearField(11); @$pb.TagNumber(15) $core.List get headers => $_getList(10); @$pb.TagNumber(18) $core.int get authType => $_getIZ(11); @$pb.TagNumber(18) set authType($core.int v) { $_setUnsignedInt32(11, v); } @$pb.TagNumber(18) $core.bool hasAuthType() => $_has(11); @$pb.TagNumber(18) void clearAuthType() => clearField(18); @$pb.TagNumber(21) $core.String get biz => $_getSZ(12); @$pb.TagNumber(21) set biz($core.String v) { $_setString(12, v); } @$pb.TagNumber(21) $core.bool hasBiz() => $_has(12); @$pb.TagNumber(21) void clearBiz() => clearField(21); @$pb.TagNumber(22) $core.String get access => $_getSZ(13); @$pb.TagNumber(22) set access($core.String v) { $_setString(13, v); } @$pb.TagNumber(22) $core.bool hasAccess() => $_has(13); @$pb.TagNumber(22) void clearAccess() => clearField(22); } class HeadersList extends $pb.GeneratedMessage { factory HeadersList() => create(); HeadersList._() : super(); factory HeadersList.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r); factory HeadersList.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r); static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'HeadersList', package: const $pb.PackageName(_omitMessageNames ? '' : 'douyin'), createEmptyInstance: create) ..aOS(1, _omitFieldNames ? '' : 'key') ..aOS(2, _omitFieldNames ? '' : 'value') ..hasRequiredFields = false ; @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.deepCopy] instead. ' 'Will be removed in next major version') HeadersList clone() => HeadersList()..mergeFromMessage(this); @$core.Deprecated( 'Using this can add significant overhead to your binary. ' 'Use [GeneratedMessageGenericExtensions.rebuild] instead. ' 'Will be removed in next major version') HeadersList copyWith(void Function(HeadersList) updates) => super.copyWith((message) => updates(message as HeadersList)) as HeadersList; $pb.BuilderInfo get info_ => _i; @$core.pragma('dart2js:noInline') static HeadersList create() => HeadersList._(); HeadersList createEmptyInstance() => create(); static $pb.PbList createRepeated() => $pb.PbList(); @$core.pragma('dart2js:noInline') static HeadersList getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor(create); static HeadersList? _defaultInstance; @$pb.TagNumber(1) $core.String get key => $_getSZ(0); @$pb.TagNumber(1) set key($core.String v) { $_setString(0, v); } @$pb.TagNumber(1) $core.bool hasKey() => $_has(0); @$pb.TagNumber(1) void clearKey() => clearField(1); @$pb.TagNumber(2) $core.String get value => $_getSZ(1); @$pb.TagNumber(2) set value($core.String v) { $_setString(1, v); } @$pb.TagNumber(2) $core.bool hasValue() => $_has(1); @$pb.TagNumber(2) void clearValue() => clearField(2); } const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); ================================================ FILE: simple_live_core/lib/src/danmaku/proto/douyin.pbenum.dart ================================================ // // Generated code. Do not modify. // source: douyin.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides, camel_case_types // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import import 'dart:core' as $core; import 'package:protobuf/protobuf.dart' as $pb; class CommentTypeTag extends $pb.ProtobufEnum { static const CommentTypeTag COMMENTTYPETAGUNKNOWN = CommentTypeTag._(0, _omitEnumNames ? '' : 'COMMENTTYPETAGUNKNOWN'); static const CommentTypeTag COMMENTTYPETAGSTAR = CommentTypeTag._(1, _omitEnumNames ? '' : 'COMMENTTYPETAGSTAR'); static const $core.List values = [ COMMENTTYPETAGUNKNOWN, COMMENTTYPETAGSTAR, ]; static final $core.Map<$core.int, CommentTypeTag> _byValue = $pb.ProtobufEnum.initByValue(values); static CommentTypeTag? valueOf($core.int value) => _byValue[value]; const CommentTypeTag._($core.int v, $core.String n) : super(v, n); } const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names'); ================================================ FILE: simple_live_core/lib/src/danmaku/proto/douyin.pbjson.dart ================================================ // // Generated code. Do not modify. // source: douyin.proto // // @dart = 2.12 // ignore_for_file: annotate_overrides, camel_case_types // ignore_for_file: constant_identifier_names, library_prefixes // ignore_for_file: non_constant_identifier_names, prefer_final_fields // ignore_for_file: unnecessary_import, unnecessary_this, unused_import import 'dart:convert' as $convert; import 'dart:core' as $core; import 'dart:typed_data' as $typed_data; @$core.Deprecated('Use commentTypeTagDescriptor instead') const CommentTypeTag$json = { '1': 'CommentTypeTag', '2': [ {'1': 'COMMENTTYPETAGUNKNOWN', '2': 0}, {'1': 'COMMENTTYPETAGSTAR', '2': 1}, ], }; /// Descriptor for `CommentTypeTag`. Decode as a `google.protobuf.EnumDescriptorProto`. final $typed_data.Uint8List commentTypeTagDescriptor = $convert.base64Decode( 'Cg5Db21tZW50VHlwZVRhZxIZChVDT01NRU5UVFlQRVRBR1VOS05PV04QABIWChJDT01NRU5UVF' 'lQRVRBR1NUQVIQAQ=='); @$core.Deprecated('Use responseDescriptor instead') const Response$json = { '1': 'Response', '2': [ {'1': 'messagesList', '3': 1, '4': 3, '5': 11, '6': '.douyin.Message', '10': 'messagesList'}, {'1': 'cursor', '3': 2, '4': 1, '5': 9, '10': 'cursor'}, {'1': 'fetchInterval', '3': 3, '4': 1, '5': 4, '10': 'fetchInterval'}, {'1': 'now', '3': 4, '4': 1, '5': 4, '10': 'now'}, {'1': 'internalExt', '3': 5, '4': 1, '5': 9, '10': 'internalExt'}, {'1': 'fetchType', '3': 6, '4': 1, '5': 13, '10': 'fetchType'}, {'1': 'routeParams', '3': 7, '4': 3, '5': 11, '6': '.douyin.Response.RouteParamsEntry', '10': 'routeParams'}, {'1': 'heartbeatDuration', '3': 8, '4': 1, '5': 4, '10': 'heartbeatDuration'}, {'1': 'needAck', '3': 9, '4': 1, '5': 8, '10': 'needAck'}, {'1': 'pushServer', '3': 10, '4': 1, '5': 9, '10': 'pushServer'}, {'1': 'liveCursor', '3': 11, '4': 1, '5': 9, '10': 'liveCursor'}, {'1': 'historyNoMore', '3': 12, '4': 1, '5': 8, '10': 'historyNoMore'}, ], '3': [Response_RouteParamsEntry$json], }; @$core.Deprecated('Use responseDescriptor instead') const Response_RouteParamsEntry$json = { '1': 'RouteParamsEntry', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, ], '7': {'7': true}, }; /// Descriptor for `Response`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List responseDescriptor = $convert.base64Decode( 'CghSZXNwb25zZRIzCgxtZXNzYWdlc0xpc3QYASADKAsyDy5kb3V5aW4uTWVzc2FnZVIMbWVzc2' 'FnZXNMaXN0EhYKBmN1cnNvchgCIAEoCVIGY3Vyc29yEiQKDWZldGNoSW50ZXJ2YWwYAyABKARS' 'DWZldGNoSW50ZXJ2YWwSEAoDbm93GAQgASgEUgNub3cSIAoLaW50ZXJuYWxFeHQYBSABKAlSC2' 'ludGVybmFsRXh0EhwKCWZldGNoVHlwZRgGIAEoDVIJZmV0Y2hUeXBlEkMKC3JvdXRlUGFyYW1z' 'GAcgAygLMiEuZG91eWluLlJlc3BvbnNlLlJvdXRlUGFyYW1zRW50cnlSC3JvdXRlUGFyYW1zEi' 'wKEWhlYXJ0YmVhdER1cmF0aW9uGAggASgEUhFoZWFydGJlYXREdXJhdGlvbhIYCgduZWVkQWNr' 'GAkgASgIUgduZWVkQWNrEh4KCnB1c2hTZXJ2ZXIYCiABKAlSCnB1c2hTZXJ2ZXISHgoKbGl2ZU' 'N1cnNvchgLIAEoCVIKbGl2ZUN1cnNvchIkCg1oaXN0b3J5Tm9Nb3JlGAwgASgIUg1oaXN0b3J5' 'Tm9Nb3JlGj4KEFJvdXRlUGFyYW1zRW50cnkSEAoDa2V5GAEgASgJUgNrZXkSFAoFdmFsdWUYAi' 'ABKAlSBXZhbHVlOgI4AQ=='); @$core.Deprecated('Use messageDescriptor instead') const Message$json = { '1': 'Message', '2': [ {'1': 'method', '3': 1, '4': 1, '5': 9, '10': 'method'}, {'1': 'payload', '3': 2, '4': 1, '5': 12, '10': 'payload'}, {'1': 'msgId', '3': 3, '4': 1, '5': 3, '10': 'msgId'}, {'1': 'msgType', '3': 4, '4': 1, '5': 5, '10': 'msgType'}, {'1': 'offset', '3': 5, '4': 1, '5': 3, '10': 'offset'}, {'1': 'needWrdsStore', '3': 6, '4': 1, '5': 8, '10': 'needWrdsStore'}, {'1': 'wrdsVersion', '3': 7, '4': 1, '5': 3, '10': 'wrdsVersion'}, {'1': 'wrdsSubKey', '3': 8, '4': 1, '5': 9, '10': 'wrdsSubKey'}, ], }; /// Descriptor for `Message`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List messageDescriptor = $convert.base64Decode( 'CgdNZXNzYWdlEhYKBm1ldGhvZBgBIAEoCVIGbWV0aG9kEhgKB3BheWxvYWQYAiABKAxSB3BheW' 'xvYWQSFAoFbXNnSWQYAyABKANSBW1zZ0lkEhgKB21zZ1R5cGUYBCABKAVSB21zZ1R5cGUSFgoG' 'b2Zmc2V0GAUgASgDUgZvZmZzZXQSJAoNbmVlZFdyZHNTdG9yZRgGIAEoCFINbmVlZFdyZHNTdG' '9yZRIgCgt3cmRzVmVyc2lvbhgHIAEoA1ILd3Jkc1ZlcnNpb24SHgoKd3Jkc1N1YktleRgIIAEo' 'CVIKd3Jkc1N1YktleQ=='); @$core.Deprecated('Use chatMessageDescriptor instead') const ChatMessage$json = { '1': 'ChatMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'content', '3': 3, '4': 1, '5': 9, '10': 'content'}, {'1': 'visibleToSender', '3': 4, '4': 1, '5': 8, '10': 'visibleToSender'}, {'1': 'backgroundImage', '3': 5, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'backgroundImage'}, {'1': 'fullScreenTextColor', '3': 6, '4': 1, '5': 9, '10': 'fullScreenTextColor'}, {'1': 'backgroundImageV2', '3': 7, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'backgroundImageV2'}, {'1': 'publicAreaCommon', '3': 8, '4': 1, '5': 11, '6': '.douyin.PublicAreaCommon', '10': 'publicAreaCommon'}, {'1': 'giftImage', '3': 9, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'giftImage'}, {'1': 'agreeMsgId', '3': 11, '4': 1, '5': 4, '10': 'agreeMsgId'}, {'1': 'priorityLevel', '3': 12, '4': 1, '5': 13, '10': 'priorityLevel'}, {'1': 'landscapeAreaCommon', '3': 13, '4': 1, '5': 11, '6': '.douyin.LandscapeAreaCommon', '10': 'landscapeAreaCommon'}, {'1': 'eventTime', '3': 15, '4': 1, '5': 4, '10': 'eventTime'}, {'1': 'sendReview', '3': 16, '4': 1, '5': 8, '10': 'sendReview'}, {'1': 'fromIntercom', '3': 17, '4': 1, '5': 8, '10': 'fromIntercom'}, {'1': 'intercomHideUserCard', '3': 18, '4': 1, '5': 8, '10': 'intercomHideUserCard'}, {'1': 'chatBy', '3': 20, '4': 1, '5': 9, '10': 'chatBy'}, {'1': 'individualChatPriority', '3': 21, '4': 1, '5': 13, '10': 'individualChatPriority'}, {'1': 'rtfContent', '3': 22, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'rtfContent'}, ], }; /// Descriptor for `ChatMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List chatMessageDescriptor = $convert.base64Decode( 'CgtDaGF0TWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb21tb24SIA' 'oEdXNlchgCIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhgKB2NvbnRlbnQYAyABKAlSB2NvbnRl' 'bnQSKAoPdmlzaWJsZVRvU2VuZGVyGAQgASgIUg92aXNpYmxlVG9TZW5kZXISNwoPYmFja2dyb3' 'VuZEltYWdlGAUgASgLMg0uZG91eWluLkltYWdlUg9iYWNrZ3JvdW5kSW1hZ2USMAoTZnVsbFNj' 'cmVlblRleHRDb2xvchgGIAEoCVITZnVsbFNjcmVlblRleHRDb2xvchI7ChFiYWNrZ3JvdW5kSW' '1hZ2VWMhgHIAEoCzINLmRvdXlpbi5JbWFnZVIRYmFja2dyb3VuZEltYWdlVjISRAoQcHVibGlj' 'QXJlYUNvbW1vbhgIIAEoCzIYLmRvdXlpbi5QdWJsaWNBcmVhQ29tbW9uUhBwdWJsaWNBcmVhQ2' '9tbW9uEisKCWdpZnRJbWFnZRgJIAEoCzINLmRvdXlpbi5JbWFnZVIJZ2lmdEltYWdlEh4KCmFn' 'cmVlTXNnSWQYCyABKARSCmFncmVlTXNnSWQSJAoNcHJpb3JpdHlMZXZlbBgMIAEoDVINcHJpb3' 'JpdHlMZXZlbBJNChNsYW5kc2NhcGVBcmVhQ29tbW9uGA0gASgLMhsuZG91eWluLkxhbmRzY2Fw' 'ZUFyZWFDb21tb25SE2xhbmRzY2FwZUFyZWFDb21tb24SHAoJZXZlbnRUaW1lGA8gASgEUglldm' 'VudFRpbWUSHgoKc2VuZFJldmlldxgQIAEoCFIKc2VuZFJldmlldxIiCgxmcm9tSW50ZXJjb20Y' 'ESABKAhSDGZyb21JbnRlcmNvbRIyChRpbnRlcmNvbUhpZGVVc2VyQ2FyZBgSIAEoCFIUaW50ZX' 'Jjb21IaWRlVXNlckNhcmQSFgoGY2hhdEJ5GBQgASgJUgZjaGF0QnkSNgoWaW5kaXZpZHVhbENo' 'YXRQcmlvcml0eRgVIAEoDVIWaW5kaXZpZHVhbENoYXRQcmlvcml0eRIsCgpydGZDb250ZW50GB' 'YgASgLMgwuZG91eWluLlRleHRSCnJ0ZkNvbnRlbnQ='); @$core.Deprecated('Use landscapeAreaCommonDescriptor instead') const LandscapeAreaCommon$json = { '1': 'LandscapeAreaCommon', '2': [ {'1': 'showHead', '3': 1, '4': 1, '5': 8, '10': 'showHead'}, {'1': 'showNickname', '3': 2, '4': 1, '5': 8, '10': 'showNickname'}, {'1': 'showFontColor', '3': 3, '4': 1, '5': 8, '10': 'showFontColor'}, {'1': 'colorValueList', '3': 4, '4': 3, '5': 9, '10': 'colorValueList'}, {'1': 'commentTypeTagsList', '3': 5, '4': 3, '5': 14, '6': '.douyin.CommentTypeTag', '10': 'commentTypeTagsList'}, ], }; /// Descriptor for `LandscapeAreaCommon`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List landscapeAreaCommonDescriptor = $convert.base64Decode( 'ChNMYW5kc2NhcGVBcmVhQ29tbW9uEhoKCHNob3dIZWFkGAEgASgIUghzaG93SGVhZBIiCgxzaG' '93Tmlja25hbWUYAiABKAhSDHNob3dOaWNrbmFtZRIkCg1zaG93Rm9udENvbG9yGAMgASgIUg1z' 'aG93Rm9udENvbG9yEiYKDmNvbG9yVmFsdWVMaXN0GAQgAygJUg5jb2xvclZhbHVlTGlzdBJICh' 'Njb21tZW50VHlwZVRhZ3NMaXN0GAUgAygOMhYuZG91eWluLkNvbW1lbnRUeXBlVGFnUhNjb21t' 'ZW50VHlwZVRhZ3NMaXN0'); @$core.Deprecated('Use roomUserSeqMessageDescriptor instead') const RoomUserSeqMessage$json = { '1': 'RoomUserSeqMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'ranksList', '3': 2, '4': 3, '5': 11, '6': '.douyin.RoomUserSeqMessageContributor', '10': 'ranksList'}, {'1': 'total', '3': 3, '4': 1, '5': 3, '10': 'total'}, {'1': 'popStr', '3': 4, '4': 1, '5': 9, '10': 'popStr'}, {'1': 'seatsList', '3': 5, '4': 3, '5': 11, '6': '.douyin.RoomUserSeqMessageContributor', '10': 'seatsList'}, {'1': 'popularity', '3': 6, '4': 1, '5': 3, '10': 'popularity'}, {'1': 'totalUser', '3': 7, '4': 1, '5': 3, '10': 'totalUser'}, {'1': 'totalUserStr', '3': 8, '4': 1, '5': 9, '10': 'totalUserStr'}, {'1': 'totalStr', '3': 9, '4': 1, '5': 9, '10': 'totalStr'}, {'1': 'onlineUserForAnchor', '3': 10, '4': 1, '5': 9, '10': 'onlineUserForAnchor'}, {'1': 'totalPvForAnchor', '3': 11, '4': 1, '5': 9, '10': 'totalPvForAnchor'}, {'1': 'upRightStatsStr', '3': 12, '4': 1, '5': 9, '10': 'upRightStatsStr'}, {'1': 'upRightStatsStrComplete', '3': 13, '4': 1, '5': 9, '10': 'upRightStatsStrComplete'}, ], }; /// Descriptor for `RoomUserSeqMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List roomUserSeqMessageDescriptor = $convert.base64Decode( 'ChJSb29tVXNlclNlcU1lc3NhZ2USJgoGY29tbW9uGAEgASgLMg4uZG91eWluLkNvbW1vblIGY2' '9tbW9uEkMKCXJhbmtzTGlzdBgCIAMoCzIlLmRvdXlpbi5Sb29tVXNlclNlcU1lc3NhZ2VDb250' 'cmlidXRvclIJcmFua3NMaXN0EhQKBXRvdGFsGAMgASgDUgV0b3RhbBIWCgZwb3BTdHIYBCABKA' 'lSBnBvcFN0chJDCglzZWF0c0xpc3QYBSADKAsyJS5kb3V5aW4uUm9vbVVzZXJTZXFNZXNzYWdl' 'Q29udHJpYnV0b3JSCXNlYXRzTGlzdBIeCgpwb3B1bGFyaXR5GAYgASgDUgpwb3B1bGFyaXR5Eh' 'wKCXRvdGFsVXNlchgHIAEoA1IJdG90YWxVc2VyEiIKDHRvdGFsVXNlclN0chgIIAEoCVIMdG90' 'YWxVc2VyU3RyEhoKCHRvdGFsU3RyGAkgASgJUgh0b3RhbFN0chIwChNvbmxpbmVVc2VyRm9yQW' '5jaG9yGAogASgJUhNvbmxpbmVVc2VyRm9yQW5jaG9yEioKEHRvdGFsUHZGb3JBbmNob3IYCyAB' 'KAlSEHRvdGFsUHZGb3JBbmNob3ISKAoPdXBSaWdodFN0YXRzU3RyGAwgASgJUg91cFJpZ2h0U3' 'RhdHNTdHISOAoXdXBSaWdodFN0YXRzU3RyQ29tcGxldGUYDSABKAlSF3VwUmlnaHRTdGF0c1N0' 'ckNvbXBsZXRl'); @$core.Deprecated('Use commonTextMessageDescriptor instead') const CommonTextMessage$json = { '1': 'CommonTextMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'scene', '3': 3, '4': 1, '5': 9, '10': 'scene'}, ], }; /// Descriptor for `CommonTextMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List commonTextMessageDescriptor = $convert.base64Decode( 'ChFDb21tb25UZXh0TWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb2' '1tb24SIAoEdXNlchgCIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhQKBXNjZW5lGAMgASgJUgVz' 'Y2VuZQ=='); @$core.Deprecated('Use updateFanTicketMessageDescriptor instead') const UpdateFanTicketMessage$json = { '1': 'UpdateFanTicketMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'roomFanTicketCountText', '3': 2, '4': 1, '5': 9, '10': 'roomFanTicketCountText'}, {'1': 'roomFanTicketCount', '3': 3, '4': 1, '5': 4, '10': 'roomFanTicketCount'}, {'1': 'forceUpdate', '3': 4, '4': 1, '5': 8, '10': 'forceUpdate'}, ], }; /// Descriptor for `UpdateFanTicketMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List updateFanTicketMessageDescriptor = $convert.base64Decode( 'ChZVcGRhdGVGYW5UaWNrZXRNZXNzYWdlEiYKBmNvbW1vbhgBIAEoCzIOLmRvdXlpbi5Db21tb2' '5SBmNvbW1vbhI2ChZyb29tRmFuVGlja2V0Q291bnRUZXh0GAIgASgJUhZyb29tRmFuVGlja2V0' 'Q291bnRUZXh0Ei4KEnJvb21GYW5UaWNrZXRDb3VudBgDIAEoBFIScm9vbUZhblRpY2tldENvdW' '50EiAKC2ZvcmNlVXBkYXRlGAQgASgIUgtmb3JjZVVwZGF0ZQ=='); @$core.Deprecated('Use roomUserSeqMessageContributorDescriptor instead') const RoomUserSeqMessageContributor$json = { '1': 'RoomUserSeqMessageContributor', '2': [ {'1': 'score', '3': 1, '4': 1, '5': 4, '10': 'score'}, {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'rank', '3': 3, '4': 1, '5': 4, '10': 'rank'}, {'1': 'delta', '3': 4, '4': 1, '5': 4, '10': 'delta'}, {'1': 'isHidden', '3': 5, '4': 1, '5': 8, '10': 'isHidden'}, {'1': 'scoreDescription', '3': 6, '4': 1, '5': 9, '10': 'scoreDescription'}, {'1': 'exactlyScore', '3': 7, '4': 1, '5': 9, '10': 'exactlyScore'}, ], }; /// Descriptor for `RoomUserSeqMessageContributor`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List roomUserSeqMessageContributorDescriptor = $convert.base64Decode( 'Ch1Sb29tVXNlclNlcU1lc3NhZ2VDb250cmlidXRvchIUCgVzY29yZRgBIAEoBFIFc2NvcmUSIA' 'oEdXNlchgCIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhIKBHJhbmsYAyABKARSBHJhbmsSFAoF' 'ZGVsdGEYBCABKARSBWRlbHRhEhoKCGlzSGlkZGVuGAUgASgIUghpc0hpZGRlbhIqChBzY29yZU' 'Rlc2NyaXB0aW9uGAYgASgJUhBzY29yZURlc2NyaXB0aW9uEiIKDGV4YWN0bHlTY29yZRgHIAEo' 'CVIMZXhhY3RseVNjb3Jl'); @$core.Deprecated('Use giftMessageDescriptor instead') const GiftMessage$json = { '1': 'GiftMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'giftId', '3': 2, '4': 1, '5': 4, '10': 'giftId'}, {'1': 'fanTicketCount', '3': 3, '4': 1, '5': 4, '10': 'fanTicketCount'}, {'1': 'groupCount', '3': 4, '4': 1, '5': 4, '10': 'groupCount'}, {'1': 'repeatCount', '3': 5, '4': 1, '5': 4, '10': 'repeatCount'}, {'1': 'comboCount', '3': 6, '4': 1, '5': 4, '10': 'comboCount'}, {'1': 'user', '3': 7, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'toUser', '3': 8, '4': 1, '5': 11, '6': '.douyin.User', '10': 'toUser'}, {'1': 'repeatEnd', '3': 9, '4': 1, '5': 13, '10': 'repeatEnd'}, {'1': 'textEffect', '3': 10, '4': 1, '5': 11, '6': '.douyin.TextEffect', '10': 'textEffect'}, {'1': 'groupId', '3': 11, '4': 1, '5': 4, '10': 'groupId'}, {'1': 'incomeTaskgifts', '3': 12, '4': 1, '5': 4, '10': 'incomeTaskgifts'}, {'1': 'roomFanTicketCount', '3': 13, '4': 1, '5': 4, '10': 'roomFanTicketCount'}, {'1': 'priority', '3': 14, '4': 1, '5': 11, '6': '.douyin.GiftIMPriority', '10': 'priority'}, {'1': 'gift', '3': 15, '4': 1, '5': 11, '6': '.douyin.GiftStruct', '10': 'gift'}, {'1': 'logId', '3': 16, '4': 1, '5': 9, '10': 'logId'}, {'1': 'sendType', '3': 17, '4': 1, '5': 4, '10': 'sendType'}, {'1': 'publicAreaCommon', '3': 18, '4': 1, '5': 11, '6': '.douyin.PublicAreaCommon', '10': 'publicAreaCommon'}, {'1': 'trayDisplayText', '3': 19, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'trayDisplayText'}, {'1': 'bannedDisplayEffects', '3': 20, '4': 1, '5': 4, '10': 'bannedDisplayEffects'}, {'1': 'displayForSelf', '3': 25, '4': 1, '5': 8, '10': 'displayForSelf'}, {'1': 'interactGiftInfo', '3': 26, '4': 1, '5': 9, '10': 'interactGiftInfo'}, {'1': 'diyItemInfo', '3': 27, '4': 1, '5': 9, '10': 'diyItemInfo'}, {'1': 'minAssetSetList', '3': 28, '4': 3, '5': 4, '10': 'minAssetSetList'}, {'1': 'totalCount', '3': 29, '4': 1, '5': 4, '10': 'totalCount'}, {'1': 'clientGiftSource', '3': 30, '4': 1, '5': 13, '10': 'clientGiftSource'}, {'1': 'toUserIdsList', '3': 32, '4': 3, '5': 4, '10': 'toUserIdsList'}, {'1': 'sendTime', '3': 33, '4': 1, '5': 4, '10': 'sendTime'}, {'1': 'forceDisplayEffects', '3': 34, '4': 1, '5': 4, '10': 'forceDisplayEffects'}, {'1': 'traceId', '3': 35, '4': 1, '5': 9, '10': 'traceId'}, {'1': 'effectDisplayTs', '3': 36, '4': 1, '5': 4, '10': 'effectDisplayTs'}, ], }; /// Descriptor for `GiftMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List giftMessageDescriptor = $convert.base64Decode( 'CgtHaWZ0TWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb21tb24SFg' 'oGZ2lmdElkGAIgASgEUgZnaWZ0SWQSJgoOZmFuVGlja2V0Q291bnQYAyABKARSDmZhblRpY2tl' 'dENvdW50Eh4KCmdyb3VwQ291bnQYBCABKARSCmdyb3VwQ291bnQSIAoLcmVwZWF0Q291bnQYBS' 'ABKARSC3JlcGVhdENvdW50Eh4KCmNvbWJvQ291bnQYBiABKARSCmNvbWJvQ291bnQSIAoEdXNl' 'chgHIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEiQKBnRvVXNlchgIIAEoCzIMLmRvdXlpbi5Vc2' 'VyUgZ0b1VzZXISHAoJcmVwZWF0RW5kGAkgASgNUglyZXBlYXRFbmQSMgoKdGV4dEVmZmVjdBgK' 'IAEoCzISLmRvdXlpbi5UZXh0RWZmZWN0Ugp0ZXh0RWZmZWN0EhgKB2dyb3VwSWQYCyABKARSB2' 'dyb3VwSWQSKAoPaW5jb21lVGFza2dpZnRzGAwgASgEUg9pbmNvbWVUYXNrZ2lmdHMSLgoScm9v' 'bUZhblRpY2tldENvdW50GA0gASgEUhJyb29tRmFuVGlja2V0Q291bnQSMgoIcHJpb3JpdHkYDi' 'ABKAsyFi5kb3V5aW4uR2lmdElNUHJpb3JpdHlSCHByaW9yaXR5EiYKBGdpZnQYDyABKAsyEi5k' 'b3V5aW4uR2lmdFN0cnVjdFIEZ2lmdBIUCgVsb2dJZBgQIAEoCVIFbG9nSWQSGgoIc2VuZFR5cG' 'UYESABKARSCHNlbmRUeXBlEkQKEHB1YmxpY0FyZWFDb21tb24YEiABKAsyGC5kb3V5aW4uUHVi' 'bGljQXJlYUNvbW1vblIQcHVibGljQXJlYUNvbW1vbhI2Cg90cmF5RGlzcGxheVRleHQYEyABKA' 'syDC5kb3V5aW4uVGV4dFIPdHJheURpc3BsYXlUZXh0EjIKFGJhbm5lZERpc3BsYXlFZmZlY3Rz' 'GBQgASgEUhRiYW5uZWREaXNwbGF5RWZmZWN0cxImCg5kaXNwbGF5Rm9yU2VsZhgZIAEoCFIOZG' 'lzcGxheUZvclNlbGYSKgoQaW50ZXJhY3RHaWZ0SW5mbxgaIAEoCVIQaW50ZXJhY3RHaWZ0SW5m' 'bxIgCgtkaXlJdGVtSW5mbxgbIAEoCVILZGl5SXRlbUluZm8SKAoPbWluQXNzZXRTZXRMaXN0GB' 'wgAygEUg9taW5Bc3NldFNldExpc3QSHgoKdG90YWxDb3VudBgdIAEoBFIKdG90YWxDb3VudBIq' 'ChBjbGllbnRHaWZ0U291cmNlGB4gASgNUhBjbGllbnRHaWZ0U291cmNlEiQKDXRvVXNlcklkc0' 'xpc3QYICADKARSDXRvVXNlcklkc0xpc3QSGgoIc2VuZFRpbWUYISABKARSCHNlbmRUaW1lEjAK' 'E2ZvcmNlRGlzcGxheUVmZmVjdHMYIiABKARSE2ZvcmNlRGlzcGxheUVmZmVjdHMSGAoHdHJhY2' 'VJZBgjIAEoCVIHdHJhY2VJZBIoCg9lZmZlY3REaXNwbGF5VHMYJCABKARSD2VmZmVjdERpc3Bs' 'YXlUcw=='); @$core.Deprecated('Use giftStructDescriptor instead') const GiftStruct$json = { '1': 'GiftStruct', '2': [ {'1': 'image', '3': 1, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'image'}, {'1': 'describe', '3': 2, '4': 1, '5': 9, '10': 'describe'}, {'1': 'notify', '3': 3, '4': 1, '5': 8, '10': 'notify'}, {'1': 'duration', '3': 4, '4': 1, '5': 4, '10': 'duration'}, {'1': 'id', '3': 5, '4': 1, '5': 4, '10': 'id'}, {'1': 'forLinkmic', '3': 7, '4': 1, '5': 8, '10': 'forLinkmic'}, {'1': 'doodle', '3': 8, '4': 1, '5': 8, '10': 'doodle'}, {'1': 'forFansclub', '3': 9, '4': 1, '5': 8, '10': 'forFansclub'}, {'1': 'combo', '3': 10, '4': 1, '5': 8, '10': 'combo'}, {'1': 'type', '3': 11, '4': 1, '5': 13, '10': 'type'}, {'1': 'diamondCount', '3': 12, '4': 1, '5': 13, '10': 'diamondCount'}, {'1': 'isDisplayedOnPanel', '3': 13, '4': 1, '5': 8, '10': 'isDisplayedOnPanel'}, {'1': 'primaryEffectId', '3': 14, '4': 1, '5': 4, '10': 'primaryEffectId'}, {'1': 'giftLabelIcon', '3': 15, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'giftLabelIcon'}, {'1': 'name', '3': 16, '4': 1, '5': 9, '10': 'name'}, {'1': 'region', '3': 17, '4': 1, '5': 9, '10': 'region'}, {'1': 'manual', '3': 18, '4': 1, '5': 9, '10': 'manual'}, {'1': 'forCustom', '3': 19, '4': 1, '5': 8, '10': 'forCustom'}, {'1': 'icon', '3': 21, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'icon'}, {'1': 'actionType', '3': 22, '4': 1, '5': 13, '10': 'actionType'}, ], }; /// Descriptor for `GiftStruct`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List giftStructDescriptor = $convert.base64Decode( 'CgpHaWZ0U3RydWN0EiMKBWltYWdlGAEgASgLMg0uZG91eWluLkltYWdlUgVpbWFnZRIaCghkZX' 'NjcmliZRgCIAEoCVIIZGVzY3JpYmUSFgoGbm90aWZ5GAMgASgIUgZub3RpZnkSGgoIZHVyYXRp' 'b24YBCABKARSCGR1cmF0aW9uEg4KAmlkGAUgASgEUgJpZBIeCgpmb3JMaW5rbWljGAcgASgIUg' 'pmb3JMaW5rbWljEhYKBmRvb2RsZRgIIAEoCFIGZG9vZGxlEiAKC2ZvckZhbnNjbHViGAkgASgI' 'Ugtmb3JGYW5zY2x1YhIUCgVjb21ibxgKIAEoCFIFY29tYm8SEgoEdHlwZRgLIAEoDVIEdHlwZR' 'IiCgxkaWFtb25kQ291bnQYDCABKA1SDGRpYW1vbmRDb3VudBIuChJpc0Rpc3BsYXllZE9uUGFu' 'ZWwYDSABKAhSEmlzRGlzcGxheWVkT25QYW5lbBIoCg9wcmltYXJ5RWZmZWN0SWQYDiABKARSD3' 'ByaW1hcnlFZmZlY3RJZBIzCg1naWZ0TGFiZWxJY29uGA8gASgLMg0uZG91eWluLkltYWdlUg1n' 'aWZ0TGFiZWxJY29uEhIKBG5hbWUYECABKAlSBG5hbWUSFgoGcmVnaW9uGBEgASgJUgZyZWdpb2' '4SFgoGbWFudWFsGBIgASgJUgZtYW51YWwSHAoJZm9yQ3VzdG9tGBMgASgIUglmb3JDdXN0b20S' 'IQoEaWNvbhgVIAEoCzINLmRvdXlpbi5JbWFnZVIEaWNvbhIeCgphY3Rpb25UeXBlGBYgASgNUg' 'phY3Rpb25UeXBl'); @$core.Deprecated('Use giftIMPriorityDescriptor instead') const GiftIMPriority$json = { '1': 'GiftIMPriority', '2': [ {'1': 'queueSizesList', '3': 1, '4': 3, '5': 4, '10': 'queueSizesList'}, {'1': 'selfQueuePriority', '3': 2, '4': 1, '5': 4, '10': 'selfQueuePriority'}, {'1': 'priority', '3': 3, '4': 1, '5': 4, '10': 'priority'}, ], }; /// Descriptor for `GiftIMPriority`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List giftIMPriorityDescriptor = $convert.base64Decode( 'Cg5HaWZ0SU1Qcmlvcml0eRImCg5xdWV1ZVNpemVzTGlzdBgBIAMoBFIOcXVldWVTaXplc0xpc3' 'QSLAoRc2VsZlF1ZXVlUHJpb3JpdHkYAiABKARSEXNlbGZRdWV1ZVByaW9yaXR5EhoKCHByaW9y' 'aXR5GAMgASgEUghwcmlvcml0eQ=='); @$core.Deprecated('Use textEffectDescriptor instead') const TextEffect$json = { '1': 'TextEffect', '2': [ {'1': 'portrait', '3': 1, '4': 1, '5': 11, '6': '.douyin.TextEffectDetail', '10': 'portrait'}, {'1': 'landscape', '3': 2, '4': 1, '5': 11, '6': '.douyin.TextEffectDetail', '10': 'landscape'}, ], }; /// Descriptor for `TextEffect`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textEffectDescriptor = $convert.base64Decode( 'CgpUZXh0RWZmZWN0EjQKCHBvcnRyYWl0GAEgASgLMhguZG91eWluLlRleHRFZmZlY3REZXRhaW' 'xSCHBvcnRyYWl0EjYKCWxhbmRzY2FwZRgCIAEoCzIYLmRvdXlpbi5UZXh0RWZmZWN0RGV0YWls' 'UglsYW5kc2NhcGU='); @$core.Deprecated('Use textEffectDetailDescriptor instead') const TextEffectDetail$json = { '1': 'TextEffectDetail', '2': [ {'1': 'text', '3': 1, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'text'}, {'1': 'textFontSize', '3': 2, '4': 1, '5': 13, '10': 'textFontSize'}, {'1': 'background', '3': 3, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'background'}, {'1': 'start', '3': 4, '4': 1, '5': 13, '10': 'start'}, {'1': 'duration', '3': 5, '4': 1, '5': 13, '10': 'duration'}, {'1': 'x', '3': 6, '4': 1, '5': 13, '10': 'x'}, {'1': 'y', '3': 7, '4': 1, '5': 13, '10': 'y'}, {'1': 'width', '3': 8, '4': 1, '5': 13, '10': 'width'}, {'1': 'height', '3': 9, '4': 1, '5': 13, '10': 'height'}, {'1': 'shadowDx', '3': 10, '4': 1, '5': 13, '10': 'shadowDx'}, {'1': 'shadowDy', '3': 11, '4': 1, '5': 13, '10': 'shadowDy'}, {'1': 'shadowRadius', '3': 12, '4': 1, '5': 13, '10': 'shadowRadius'}, {'1': 'shadowColor', '3': 13, '4': 1, '5': 9, '10': 'shadowColor'}, {'1': 'strokeColor', '3': 14, '4': 1, '5': 9, '10': 'strokeColor'}, {'1': 'strokeWidth', '3': 15, '4': 1, '5': 13, '10': 'strokeWidth'}, ], }; /// Descriptor for `TextEffectDetail`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textEffectDetailDescriptor = $convert.base64Decode( 'ChBUZXh0RWZmZWN0RGV0YWlsEiAKBHRleHQYASABKAsyDC5kb3V5aW4uVGV4dFIEdGV4dBIiCg' 'x0ZXh0Rm9udFNpemUYAiABKA1SDHRleHRGb250U2l6ZRItCgpiYWNrZ3JvdW5kGAMgASgLMg0u' 'ZG91eWluLkltYWdlUgpiYWNrZ3JvdW5kEhQKBXN0YXJ0GAQgASgNUgVzdGFydBIaCghkdXJhdG' 'lvbhgFIAEoDVIIZHVyYXRpb24SDAoBeBgGIAEoDVIBeBIMCgF5GAcgASgNUgF5EhQKBXdpZHRo' 'GAggASgNUgV3aWR0aBIWCgZoZWlnaHQYCSABKA1SBmhlaWdodBIaCghzaGFkb3dEeBgKIAEoDV' 'IIc2hhZG93RHgSGgoIc2hhZG93RHkYCyABKA1SCHNoYWRvd0R5EiIKDHNoYWRvd1JhZGl1cxgM' 'IAEoDVIMc2hhZG93UmFkaXVzEiAKC3NoYWRvd0NvbG9yGA0gASgJUgtzaGFkb3dDb2xvchIgCg' 'tzdHJva2VDb2xvchgOIAEoCVILc3Ryb2tlQ29sb3ISIAoLc3Ryb2tlV2lkdGgYDyABKA1SC3N0' 'cm9rZVdpZHRo'); @$core.Deprecated('Use memberMessageDescriptor instead') const MemberMessage$json = { '1': 'MemberMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'memberCount', '3': 3, '4': 1, '5': 4, '10': 'memberCount'}, {'1': 'operator', '3': 4, '4': 1, '5': 11, '6': '.douyin.User', '10': 'operator'}, {'1': 'isSetToAdmin', '3': 5, '4': 1, '5': 8, '10': 'isSetToAdmin'}, {'1': 'isTopUser', '3': 6, '4': 1, '5': 8, '10': 'isTopUser'}, {'1': 'rankScore', '3': 7, '4': 1, '5': 4, '10': 'rankScore'}, {'1': 'topUserNo', '3': 8, '4': 1, '5': 4, '10': 'topUserNo'}, {'1': 'enterType', '3': 9, '4': 1, '5': 4, '10': 'enterType'}, {'1': 'action', '3': 10, '4': 1, '5': 4, '10': 'action'}, {'1': 'actionDescription', '3': 11, '4': 1, '5': 9, '10': 'actionDescription'}, {'1': 'userId', '3': 12, '4': 1, '5': 4, '10': 'userId'}, {'1': 'effectConfig', '3': 13, '4': 1, '5': 11, '6': '.douyin.EffectConfig', '10': 'effectConfig'}, {'1': 'popStr', '3': 14, '4': 1, '5': 9, '10': 'popStr'}, {'1': 'enterEffectConfig', '3': 15, '4': 1, '5': 11, '6': '.douyin.EffectConfig', '10': 'enterEffectConfig'}, {'1': 'backgroundImage', '3': 16, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'backgroundImage'}, {'1': 'backgroundImageV2', '3': 17, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'backgroundImageV2'}, {'1': 'anchorDisplayText', '3': 18, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'anchorDisplayText'}, {'1': 'publicAreaCommon', '3': 19, '4': 1, '5': 11, '6': '.douyin.PublicAreaCommon', '10': 'publicAreaCommon'}, {'1': 'userEnterTipType', '3': 20, '4': 1, '5': 4, '10': 'userEnterTipType'}, {'1': 'anchorEnterTipType', '3': 21, '4': 1, '5': 4, '10': 'anchorEnterTipType'}, ], }; /// Descriptor for `MemberMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List memberMessageDescriptor = $convert.base64Decode( 'Cg1NZW1iZXJNZXNzYWdlEiYKBmNvbW1vbhgBIAEoCzIOLmRvdXlpbi5Db21tb25SBmNvbW1vbh' 'IgCgR1c2VyGAIgASgLMgwuZG91eWluLlVzZXJSBHVzZXISIAoLbWVtYmVyQ291bnQYAyABKARS' 'C21lbWJlckNvdW50EigKCG9wZXJhdG9yGAQgASgLMgwuZG91eWluLlVzZXJSCG9wZXJhdG9yEi' 'IKDGlzU2V0VG9BZG1pbhgFIAEoCFIMaXNTZXRUb0FkbWluEhwKCWlzVG9wVXNlchgGIAEoCFIJ' 'aXNUb3BVc2VyEhwKCXJhbmtTY29yZRgHIAEoBFIJcmFua1Njb3JlEhwKCXRvcFVzZXJObxgIIA' 'EoBFIJdG9wVXNlck5vEhwKCWVudGVyVHlwZRgJIAEoBFIJZW50ZXJUeXBlEhYKBmFjdGlvbhgK' 'IAEoBFIGYWN0aW9uEiwKEWFjdGlvbkRlc2NyaXB0aW9uGAsgASgJUhFhY3Rpb25EZXNjcmlwdG' 'lvbhIWCgZ1c2VySWQYDCABKARSBnVzZXJJZBI4CgxlZmZlY3RDb25maWcYDSABKAsyFC5kb3V5' 'aW4uRWZmZWN0Q29uZmlnUgxlZmZlY3RDb25maWcSFgoGcG9wU3RyGA4gASgJUgZwb3BTdHISQg' 'oRZW50ZXJFZmZlY3RDb25maWcYDyABKAsyFC5kb3V5aW4uRWZmZWN0Q29uZmlnUhFlbnRlckVm' 'ZmVjdENvbmZpZxI3Cg9iYWNrZ3JvdW5kSW1hZ2UYECABKAsyDS5kb3V5aW4uSW1hZ2VSD2JhY2' 'tncm91bmRJbWFnZRI7ChFiYWNrZ3JvdW5kSW1hZ2VWMhgRIAEoCzINLmRvdXlpbi5JbWFnZVIR' 'YmFja2dyb3VuZEltYWdlVjISOgoRYW5jaG9yRGlzcGxheVRleHQYEiABKAsyDC5kb3V5aW4uVG' 'V4dFIRYW5jaG9yRGlzcGxheVRleHQSRAoQcHVibGljQXJlYUNvbW1vbhgTIAEoCzIYLmRvdXlp' 'bi5QdWJsaWNBcmVhQ29tbW9uUhBwdWJsaWNBcmVhQ29tbW9uEioKEHVzZXJFbnRlclRpcFR5cG' 'UYFCABKARSEHVzZXJFbnRlclRpcFR5cGUSLgoSYW5jaG9yRW50ZXJUaXBUeXBlGBUgASgEUhJh' 'bmNob3JFbnRlclRpcFR5cGU='); @$core.Deprecated('Use publicAreaCommonDescriptor instead') const PublicAreaCommon$json = { '1': 'PublicAreaCommon', '2': [ {'1': 'userLabel', '3': 1, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'userLabel'}, {'1': 'userConsumeInRoom', '3': 2, '4': 1, '5': 4, '10': 'userConsumeInRoom'}, {'1': 'userSendGiftCntInRoom', '3': 3, '4': 1, '5': 4, '10': 'userSendGiftCntInRoom'}, ], }; /// Descriptor for `PublicAreaCommon`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List publicAreaCommonDescriptor = $convert.base64Decode( 'ChBQdWJsaWNBcmVhQ29tbW9uEisKCXVzZXJMYWJlbBgBIAEoCzINLmRvdXlpbi5JbWFnZVIJdX' 'NlckxhYmVsEiwKEXVzZXJDb25zdW1lSW5Sb29tGAIgASgEUhF1c2VyQ29uc3VtZUluUm9vbRI0' 'ChV1c2VyU2VuZEdpZnRDbnRJblJvb20YAyABKARSFXVzZXJTZW5kR2lmdENudEluUm9vbQ=='); @$core.Deprecated('Use effectConfigDescriptor instead') const EffectConfig$json = { '1': 'EffectConfig', '2': [ {'1': 'type', '3': 1, '4': 1, '5': 4, '10': 'type'}, {'1': 'icon', '3': 2, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'icon'}, {'1': 'avatarPos', '3': 3, '4': 1, '5': 4, '10': 'avatarPos'}, {'1': 'text', '3': 4, '4': 1, '5': 11, '6': '.douyin.Text', '10': 'text'}, {'1': 'textIcon', '3': 5, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'textIcon'}, {'1': 'stayTime', '3': 6, '4': 1, '5': 13, '10': 'stayTime'}, {'1': 'animAssetId', '3': 7, '4': 1, '5': 4, '10': 'animAssetId'}, {'1': 'badge', '3': 8, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'badge'}, {'1': 'flexSettingArrayList', '3': 9, '4': 3, '5': 4, '10': 'flexSettingArrayList'}, {'1': 'textIconOverlay', '3': 10, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'textIconOverlay'}, {'1': 'animatedBadge', '3': 11, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'animatedBadge'}, {'1': 'hasSweepLight', '3': 12, '4': 1, '5': 8, '10': 'hasSweepLight'}, {'1': 'textFlexSettingArrayList', '3': 13, '4': 3, '5': 4, '10': 'textFlexSettingArrayList'}, {'1': 'centerAnimAssetId', '3': 14, '4': 1, '5': 4, '10': 'centerAnimAssetId'}, {'1': 'dynamicImage', '3': 15, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'dynamicImage'}, {'1': 'extraMap', '3': 16, '4': 3, '5': 11, '6': '.douyin.EffectConfig.ExtraMapEntry', '10': 'extraMap'}, {'1': 'mp4AnimAssetId', '3': 17, '4': 1, '5': 4, '10': 'mp4AnimAssetId'}, {'1': 'priority', '3': 18, '4': 1, '5': 4, '10': 'priority'}, {'1': 'maxWaitTime', '3': 19, '4': 1, '5': 4, '10': 'maxWaitTime'}, {'1': 'dressId', '3': 20, '4': 1, '5': 9, '10': 'dressId'}, {'1': 'alignment', '3': 21, '4': 1, '5': 4, '10': 'alignment'}, {'1': 'alignmentOffset', '3': 22, '4': 1, '5': 4, '10': 'alignmentOffset'}, ], '3': [EffectConfig_ExtraMapEntry$json], }; @$core.Deprecated('Use effectConfigDescriptor instead') const EffectConfig_ExtraMapEntry$json = { '1': 'ExtraMapEntry', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, ], '7': {'7': true}, }; /// Descriptor for `EffectConfig`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List effectConfigDescriptor = $convert.base64Decode( 'CgxFZmZlY3RDb25maWcSEgoEdHlwZRgBIAEoBFIEdHlwZRIhCgRpY29uGAIgASgLMg0uZG91eW' 'luLkltYWdlUgRpY29uEhwKCWF2YXRhclBvcxgDIAEoBFIJYXZhdGFyUG9zEiAKBHRleHQYBCAB' 'KAsyDC5kb3V5aW4uVGV4dFIEdGV4dBIpCgh0ZXh0SWNvbhgFIAEoCzINLmRvdXlpbi5JbWFnZV' 'IIdGV4dEljb24SGgoIc3RheVRpbWUYBiABKA1SCHN0YXlUaW1lEiAKC2FuaW1Bc3NldElkGAcg' 'ASgEUgthbmltQXNzZXRJZBIjCgViYWRnZRgIIAEoCzINLmRvdXlpbi5JbWFnZVIFYmFkZ2USMg' 'oUZmxleFNldHRpbmdBcnJheUxpc3QYCSADKARSFGZsZXhTZXR0aW5nQXJyYXlMaXN0EjcKD3Rl' 'eHRJY29uT3ZlcmxheRgKIAEoCzINLmRvdXlpbi5JbWFnZVIPdGV4dEljb25PdmVybGF5EjMKDW' 'FuaW1hdGVkQmFkZ2UYCyABKAsyDS5kb3V5aW4uSW1hZ2VSDWFuaW1hdGVkQmFkZ2USJAoNaGFz' 'U3dlZXBMaWdodBgMIAEoCFINaGFzU3dlZXBMaWdodBI6Chh0ZXh0RmxleFNldHRpbmdBcnJheU' 'xpc3QYDSADKARSGHRleHRGbGV4U2V0dGluZ0FycmF5TGlzdBIsChFjZW50ZXJBbmltQXNzZXRJ' 'ZBgOIAEoBFIRY2VudGVyQW5pbUFzc2V0SWQSMQoMZHluYW1pY0ltYWdlGA8gASgLMg0uZG91eW' 'luLkltYWdlUgxkeW5hbWljSW1hZ2USPgoIZXh0cmFNYXAYECADKAsyIi5kb3V5aW4uRWZmZWN0' 'Q29uZmlnLkV4dHJhTWFwRW50cnlSCGV4dHJhTWFwEiYKDm1wNEFuaW1Bc3NldElkGBEgASgEUg' '5tcDRBbmltQXNzZXRJZBIaCghwcmlvcml0eRgSIAEoBFIIcHJpb3JpdHkSIAoLbWF4V2FpdFRp' 'bWUYEyABKARSC21heFdhaXRUaW1lEhgKB2RyZXNzSWQYFCABKAlSB2RyZXNzSWQSHAoJYWxpZ2' '5tZW50GBUgASgEUglhbGlnbm1lbnQSKAoPYWxpZ25tZW50T2Zmc2V0GBYgASgEUg9hbGlnbm1l' 'bnRPZmZzZXQaOwoNRXh0cmFNYXBFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIA' 'EoCVIFdmFsdWU6AjgB'); @$core.Deprecated('Use textDescriptor instead') const Text$json = { '1': 'Text', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'defaultPatter', '3': 2, '4': 1, '5': 9, '10': 'defaultPatter'}, {'1': 'defaultFormat', '3': 3, '4': 1, '5': 11, '6': '.douyin.TextFormat', '10': 'defaultFormat'}, {'1': 'piecesList', '3': 4, '4': 3, '5': 11, '6': '.douyin.TextPiece', '10': 'piecesList'}, ], }; /// Descriptor for `Text`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textDescriptor = $convert.base64Decode( 'CgRUZXh0EhAKA2tleRgBIAEoCVIDa2V5EiQKDWRlZmF1bHRQYXR0ZXIYAiABKAlSDWRlZmF1bH' 'RQYXR0ZXISOAoNZGVmYXVsdEZvcm1hdBgDIAEoCzISLmRvdXlpbi5UZXh0Rm9ybWF0Ug1kZWZh' 'dWx0Rm9ybWF0EjEKCnBpZWNlc0xpc3QYBCADKAsyES5kb3V5aW4uVGV4dFBpZWNlUgpwaWVjZX' 'NMaXN0'); @$core.Deprecated('Use textPieceDescriptor instead') const TextPiece$json = { '1': 'TextPiece', '2': [ {'1': 'type', '3': 1, '4': 1, '5': 8, '10': 'type'}, {'1': 'format', '3': 2, '4': 1, '5': 11, '6': '.douyin.TextFormat', '10': 'format'}, {'1': 'stringValue', '3': 3, '4': 1, '5': 9, '10': 'stringValue'}, {'1': 'userValue', '3': 4, '4': 1, '5': 11, '6': '.douyin.TextPieceUser', '10': 'userValue'}, {'1': 'giftValue', '3': 5, '4': 1, '5': 11, '6': '.douyin.TextPieceGift', '10': 'giftValue'}, {'1': 'heartValue', '3': 6, '4': 1, '5': 11, '6': '.douyin.TextPieceHeart', '10': 'heartValue'}, {'1': 'patternRefValue', '3': 7, '4': 1, '5': 11, '6': '.douyin.TextPiecePatternRef', '10': 'patternRefValue'}, {'1': 'imageValue', '3': 8, '4': 1, '5': 11, '6': '.douyin.TextPieceImage', '10': 'imageValue'}, ], }; /// Descriptor for `TextPiece`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textPieceDescriptor = $convert.base64Decode( 'CglUZXh0UGllY2USEgoEdHlwZRgBIAEoCFIEdHlwZRIqCgZmb3JtYXQYAiABKAsyEi5kb3V5aW' '4uVGV4dEZvcm1hdFIGZm9ybWF0EiAKC3N0cmluZ1ZhbHVlGAMgASgJUgtzdHJpbmdWYWx1ZRIz' 'Cgl1c2VyVmFsdWUYBCABKAsyFS5kb3V5aW4uVGV4dFBpZWNlVXNlclIJdXNlclZhbHVlEjMKCW' 'dpZnRWYWx1ZRgFIAEoCzIVLmRvdXlpbi5UZXh0UGllY2VHaWZ0UglnaWZ0VmFsdWUSNgoKaGVh' 'cnRWYWx1ZRgGIAEoCzIWLmRvdXlpbi5UZXh0UGllY2VIZWFydFIKaGVhcnRWYWx1ZRJFCg9wYX' 'R0ZXJuUmVmVmFsdWUYByABKAsyGy5kb3V5aW4uVGV4dFBpZWNlUGF0dGVyblJlZlIPcGF0dGVy' 'blJlZlZhbHVlEjYKCmltYWdlVmFsdWUYCCABKAsyFi5kb3V5aW4uVGV4dFBpZWNlSW1hZ2VSCm' 'ltYWdlVmFsdWU='); @$core.Deprecated('Use textPieceImageDescriptor instead') const TextPieceImage$json = { '1': 'TextPieceImage', '2': [ {'1': 'image', '3': 1, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'image'}, {'1': 'scalingRate', '3': 2, '4': 1, '5': 2, '10': 'scalingRate'}, ], }; /// Descriptor for `TextPieceImage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textPieceImageDescriptor = $convert.base64Decode( 'Cg5UZXh0UGllY2VJbWFnZRIjCgVpbWFnZRgBIAEoCzINLmRvdXlpbi5JbWFnZVIFaW1hZ2USIA' 'oLc2NhbGluZ1JhdGUYAiABKAJSC3NjYWxpbmdSYXRl'); @$core.Deprecated('Use textPiecePatternRefDescriptor instead') const TextPiecePatternRef$json = { '1': 'TextPiecePatternRef', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'defaultPattern', '3': 2, '4': 1, '5': 9, '10': 'defaultPattern'}, ], }; /// Descriptor for `TextPiecePatternRef`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textPiecePatternRefDescriptor = $convert.base64Decode( 'ChNUZXh0UGllY2VQYXR0ZXJuUmVmEhAKA2tleRgBIAEoCVIDa2V5EiYKDmRlZmF1bHRQYXR0ZX' 'JuGAIgASgJUg5kZWZhdWx0UGF0dGVybg=='); @$core.Deprecated('Use textPieceHeartDescriptor instead') const TextPieceHeart$json = { '1': 'TextPieceHeart', '2': [ {'1': 'color', '3': 1, '4': 1, '5': 9, '10': 'color'}, ], }; /// Descriptor for `TextPieceHeart`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textPieceHeartDescriptor = $convert.base64Decode( 'Cg5UZXh0UGllY2VIZWFydBIUCgVjb2xvchgBIAEoCVIFY29sb3I='); @$core.Deprecated('Use textPieceGiftDescriptor instead') const TextPieceGift$json = { '1': 'TextPieceGift', '2': [ {'1': 'giftId', '3': 1, '4': 1, '5': 4, '10': 'giftId'}, {'1': 'nameRef', '3': 2, '4': 1, '5': 11, '6': '.douyin.PatternRef', '10': 'nameRef'}, ], }; /// Descriptor for `TextPieceGift`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textPieceGiftDescriptor = $convert.base64Decode( 'Cg1UZXh0UGllY2VHaWZ0EhYKBmdpZnRJZBgBIAEoBFIGZ2lmdElkEiwKB25hbWVSZWYYAiABKA' 'syEi5kb3V5aW4uUGF0dGVyblJlZlIHbmFtZVJlZg=='); @$core.Deprecated('Use patternRefDescriptor instead') const PatternRef$json = { '1': 'PatternRef', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'defaultPattern', '3': 2, '4': 1, '5': 9, '10': 'defaultPattern'}, ], }; /// Descriptor for `PatternRef`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List patternRefDescriptor = $convert.base64Decode( 'CgpQYXR0ZXJuUmVmEhAKA2tleRgBIAEoCVIDa2V5EiYKDmRlZmF1bHRQYXR0ZXJuGAIgASgJUg' '5kZWZhdWx0UGF0dGVybg=='); @$core.Deprecated('Use textPieceUserDescriptor instead') const TextPieceUser$json = { '1': 'TextPieceUser', '2': [ {'1': 'user', '3': 1, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'withColon', '3': 2, '4': 1, '5': 8, '10': 'withColon'}, ], }; /// Descriptor for `TextPieceUser`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textPieceUserDescriptor = $convert.base64Decode( 'Cg1UZXh0UGllY2VVc2VyEiAKBHVzZXIYASABKAsyDC5kb3V5aW4uVXNlclIEdXNlchIcCgl3aX' 'RoQ29sb24YAiABKAhSCXdpdGhDb2xvbg=='); @$core.Deprecated('Use textFormatDescriptor instead') const TextFormat$json = { '1': 'TextFormat', '2': [ {'1': 'color', '3': 1, '4': 1, '5': 9, '10': 'color'}, {'1': 'bold', '3': 2, '4': 1, '5': 8, '10': 'bold'}, {'1': 'italic', '3': 3, '4': 1, '5': 8, '10': 'italic'}, {'1': 'weight', '3': 4, '4': 1, '5': 13, '10': 'weight'}, {'1': 'italicAngle', '3': 5, '4': 1, '5': 13, '10': 'italicAngle'}, {'1': 'fontSize', '3': 6, '4': 1, '5': 13, '10': 'fontSize'}, {'1': 'useHeighLightColor', '3': 7, '4': 1, '5': 8, '10': 'useHeighLightColor'}, {'1': 'useRemoteClor', '3': 8, '4': 1, '5': 8, '10': 'useRemoteClor'}, ], }; /// Descriptor for `TextFormat`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List textFormatDescriptor = $convert.base64Decode( 'CgpUZXh0Rm9ybWF0EhQKBWNvbG9yGAEgASgJUgVjb2xvchISCgRib2xkGAIgASgIUgRib2xkEh' 'YKBml0YWxpYxgDIAEoCFIGaXRhbGljEhYKBndlaWdodBgEIAEoDVIGd2VpZ2h0EiAKC2l0YWxp' 'Y0FuZ2xlGAUgASgNUgtpdGFsaWNBbmdsZRIaCghmb250U2l6ZRgGIAEoDVIIZm9udFNpemUSLg' 'oSdXNlSGVpZ2hMaWdodENvbG9yGAcgASgIUhJ1c2VIZWlnaExpZ2h0Q29sb3ISJAoNdXNlUmVt' 'b3RlQ2xvchgIIAEoCFINdXNlUmVtb3RlQ2xvcg=='); @$core.Deprecated('Use likeMessageDescriptor instead') const LikeMessage$json = { '1': 'LikeMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'count', '3': 2, '4': 1, '5': 4, '10': 'count'}, {'1': 'total', '3': 3, '4': 1, '5': 4, '10': 'total'}, {'1': 'color', '3': 4, '4': 1, '5': 4, '10': 'color'}, {'1': 'user', '3': 5, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'icon', '3': 6, '4': 1, '5': 9, '10': 'icon'}, {'1': 'doubleLikeDetail', '3': 7, '4': 1, '5': 11, '6': '.douyin.DoubleLikeDetail', '10': 'doubleLikeDetail'}, {'1': 'displayControlInfo', '3': 8, '4': 1, '5': 11, '6': '.douyin.DisplayControlInfo', '10': 'displayControlInfo'}, {'1': 'linkmicGuestUid', '3': 9, '4': 1, '5': 4, '10': 'linkmicGuestUid'}, {'1': 'scene', '3': 10, '4': 1, '5': 9, '10': 'scene'}, {'1': 'picoDisplayInfo', '3': 11, '4': 1, '5': 11, '6': '.douyin.PicoDisplayInfo', '10': 'picoDisplayInfo'}, ], }; /// Descriptor for `LikeMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List likeMessageDescriptor = $convert.base64Decode( 'CgtMaWtlTWVzc2FnZRImCgZjb21tb24YASABKAsyDi5kb3V5aW4uQ29tbW9uUgZjb21tb24SFA' 'oFY291bnQYAiABKARSBWNvdW50EhQKBXRvdGFsGAMgASgEUgV0b3RhbBIUCgVjb2xvchgEIAEo' 'BFIFY29sb3ISIAoEdXNlchgFIAEoCzIMLmRvdXlpbi5Vc2VyUgR1c2VyEhIKBGljb24YBiABKA' 'lSBGljb24SRAoQZG91YmxlTGlrZURldGFpbBgHIAEoCzIYLmRvdXlpbi5Eb3VibGVMaWtlRGV0' 'YWlsUhBkb3VibGVMaWtlRGV0YWlsEkoKEmRpc3BsYXlDb250cm9sSW5mbxgIIAEoCzIaLmRvdX' 'lpbi5EaXNwbGF5Q29udHJvbEluZm9SEmRpc3BsYXlDb250cm9sSW5mbxIoCg9saW5rbWljR3Vl' 'c3RVaWQYCSABKARSD2xpbmttaWNHdWVzdFVpZBIUCgVzY2VuZRgKIAEoCVIFc2NlbmUSQQoPcG' 'ljb0Rpc3BsYXlJbmZvGAsgASgLMhcuZG91eWluLlBpY29EaXNwbGF5SW5mb1IPcGljb0Rpc3Bs' 'YXlJbmZv'); @$core.Deprecated('Use socialMessageDescriptor instead') const SocialMessage$json = { '1': 'SocialMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'shareType', '3': 3, '4': 1, '5': 4, '10': 'shareType'}, {'1': 'action', '3': 4, '4': 1, '5': 4, '10': 'action'}, {'1': 'shareTarget', '3': 5, '4': 1, '5': 9, '10': 'shareTarget'}, {'1': 'followCount', '3': 6, '4': 1, '5': 4, '10': 'followCount'}, {'1': 'publicAreaCommon', '3': 7, '4': 1, '5': 11, '6': '.douyin.PublicAreaCommon', '10': 'publicAreaCommon'}, ], }; /// Descriptor for `SocialMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List socialMessageDescriptor = $convert.base64Decode( 'Cg1Tb2NpYWxNZXNzYWdlEiYKBmNvbW1vbhgBIAEoCzIOLmRvdXlpbi5Db21tb25SBmNvbW1vbh' 'IgCgR1c2VyGAIgASgLMgwuZG91eWluLlVzZXJSBHVzZXISHAoJc2hhcmVUeXBlGAMgASgEUglz' 'aGFyZVR5cGUSFgoGYWN0aW9uGAQgASgEUgZhY3Rpb24SIAoLc2hhcmVUYXJnZXQYBSABKAlSC3' 'NoYXJlVGFyZ2V0EiAKC2ZvbGxvd0NvdW50GAYgASgEUgtmb2xsb3dDb3VudBJEChBwdWJsaWNB' 'cmVhQ29tbW9uGAcgASgLMhguZG91eWluLlB1YmxpY0FyZWFDb21tb25SEHB1YmxpY0FyZWFDb2' '1tb24='); @$core.Deprecated('Use picoDisplayInfoDescriptor instead') const PicoDisplayInfo$json = { '1': 'PicoDisplayInfo', '2': [ {'1': 'comboSumCount', '3': 1, '4': 1, '5': 4, '10': 'comboSumCount'}, {'1': 'emoji', '3': 2, '4': 1, '5': 9, '10': 'emoji'}, {'1': 'emojiIcon', '3': 3, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'emojiIcon'}, {'1': 'emojiText', '3': 4, '4': 1, '5': 9, '10': 'emojiText'}, ], }; /// Descriptor for `PicoDisplayInfo`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List picoDisplayInfoDescriptor = $convert.base64Decode( 'Cg9QaWNvRGlzcGxheUluZm8SJAoNY29tYm9TdW1Db3VudBgBIAEoBFINY29tYm9TdW1Db3VudB' 'IUCgVlbW9qaRgCIAEoCVIFZW1vamkSKwoJZW1vamlJY29uGAMgASgLMg0uZG91eWluLkltYWdl' 'UgllbW9qaUljb24SHAoJZW1vamlUZXh0GAQgASgJUgllbW9qaVRleHQ='); @$core.Deprecated('Use doubleLikeDetailDescriptor instead') const DoubleLikeDetail$json = { '1': 'DoubleLikeDetail', '2': [ {'1': 'doubleFlag', '3': 1, '4': 1, '5': 8, '10': 'doubleFlag'}, {'1': 'seqId', '3': 2, '4': 1, '5': 13, '10': 'seqId'}, {'1': 'renewalsNum', '3': 3, '4': 1, '5': 13, '10': 'renewalsNum'}, {'1': 'triggersNum', '3': 4, '4': 1, '5': 13, '10': 'triggersNum'}, ], }; /// Descriptor for `DoubleLikeDetail`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List doubleLikeDetailDescriptor = $convert.base64Decode( 'ChBEb3VibGVMaWtlRGV0YWlsEh4KCmRvdWJsZUZsYWcYASABKAhSCmRvdWJsZUZsYWcSFAoFc2' 'VxSWQYAiABKA1SBXNlcUlkEiAKC3JlbmV3YWxzTnVtGAMgASgNUgtyZW5ld2Fsc051bRIgCgt0' 'cmlnZ2Vyc051bRgEIAEoDVILdHJpZ2dlcnNOdW0='); @$core.Deprecated('Use displayControlInfoDescriptor instead') const DisplayControlInfo$json = { '1': 'DisplayControlInfo', '2': [ {'1': 'showText', '3': 1, '4': 1, '5': 8, '10': 'showText'}, {'1': 'showIcons', '3': 2, '4': 1, '5': 8, '10': 'showIcons'}, ], }; /// Descriptor for `DisplayControlInfo`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List displayControlInfoDescriptor = $convert.base64Decode( 'ChJEaXNwbGF5Q29udHJvbEluZm8SGgoIc2hvd1RleHQYASABKAhSCHNob3dUZXh0EhwKCXNob3' 'dJY29ucxgCIAEoCFIJc2hvd0ljb25z'); @$core.Deprecated('Use episodeChatMessageDescriptor instead') const EpisodeChatMessage$json = { '1': 'EpisodeChatMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Message', '10': 'common'}, {'1': 'user', '3': 2, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'content', '3': 3, '4': 1, '5': 9, '10': 'content'}, {'1': 'visibleToSende', '3': 4, '4': 1, '5': 8, '10': 'visibleToSende'}, {'1': 'giftImage', '3': 7, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'giftImage'}, {'1': 'agreeMsgId', '3': 8, '4': 1, '5': 4, '10': 'agreeMsgId'}, {'1': 'colorValueList', '3': 9, '4': 3, '5': 9, '10': 'colorValueList'}, ], }; /// Descriptor for `EpisodeChatMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List episodeChatMessageDescriptor = $convert.base64Decode( 'ChJFcGlzb2RlQ2hhdE1lc3NhZ2USJwoGY29tbW9uGAEgASgLMg8uZG91eWluLk1lc3NhZ2VSBm' 'NvbW1vbhIgCgR1c2VyGAIgASgLMgwuZG91eWluLlVzZXJSBHVzZXISGAoHY29udGVudBgDIAEo' 'CVIHY29udGVudBImCg52aXNpYmxlVG9TZW5kZRgEIAEoCFIOdmlzaWJsZVRvU2VuZGUSKwoJZ2' 'lmdEltYWdlGAcgASgLMg0uZG91eWluLkltYWdlUglnaWZ0SW1hZ2USHgoKYWdyZWVNc2dJZBgI' 'IAEoBFIKYWdyZWVNc2dJZBImCg5jb2xvclZhbHVlTGlzdBgJIAMoCVIOY29sb3JWYWx1ZUxpc3' 'Q='); @$core.Deprecated('Use matchAgainstScoreMessageDescriptor instead') const MatchAgainstScoreMessage$json = { '1': 'MatchAgainstScoreMessage', '2': [ {'1': 'common', '3': 1, '4': 1, '5': 11, '6': '.douyin.Common', '10': 'common'}, {'1': 'against', '3': 2, '4': 1, '5': 11, '6': '.douyin.Against', '10': 'against'}, {'1': 'matchStatus', '3': 3, '4': 1, '5': 13, '10': 'matchStatus'}, {'1': 'displayStatus', '3': 4, '4': 1, '5': 13, '10': 'displayStatus'}, ], }; /// Descriptor for `MatchAgainstScoreMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List matchAgainstScoreMessageDescriptor = $convert.base64Decode( 'ChhNYXRjaEFnYWluc3RTY29yZU1lc3NhZ2USJgoGY29tbW9uGAEgASgLMg4uZG91eWluLkNvbW' '1vblIGY29tbW9uEikKB2FnYWluc3QYAiABKAsyDy5kb3V5aW4uQWdhaW5zdFIHYWdhaW5zdBIg' 'CgttYXRjaFN0YXR1cxgDIAEoDVILbWF0Y2hTdGF0dXMSJAoNZGlzcGxheVN0YXR1cxgEIAEoDV' 'INZGlzcGxheVN0YXR1cw=='); @$core.Deprecated('Use againstDescriptor instead') const Against$json = { '1': 'Against', '2': [ {'1': 'leftName', '3': 1, '4': 1, '5': 9, '10': 'leftName'}, {'1': 'leftLogo', '3': 2, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'leftLogo'}, {'1': 'leftGoal', '3': 3, '4': 1, '5': 9, '10': 'leftGoal'}, {'1': 'rightName', '3': 6, '4': 1, '5': 9, '10': 'rightName'}, {'1': 'rightLogo', '3': 7, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'rightLogo'}, {'1': 'rightGoal', '3': 8, '4': 1, '5': 9, '10': 'rightGoal'}, {'1': 'timestamp', '3': 11, '4': 1, '5': 4, '10': 'timestamp'}, {'1': 'version', '3': 12, '4': 1, '5': 4, '10': 'version'}, {'1': 'leftTeamId', '3': 13, '4': 1, '5': 4, '10': 'leftTeamId'}, {'1': 'rightTeamId', '3': 14, '4': 1, '5': 4, '10': 'rightTeamId'}, {'1': 'diffSei2absSecond', '3': 15, '4': 1, '5': 4, '10': 'diffSei2absSecond'}, {'1': 'finalGoalStage', '3': 16, '4': 1, '5': 13, '10': 'finalGoalStage'}, {'1': 'currentGoalStage', '3': 17, '4': 1, '5': 13, '10': 'currentGoalStage'}, {'1': 'leftScoreAddition', '3': 18, '4': 1, '5': 13, '10': 'leftScoreAddition'}, {'1': 'rightScoreAddition', '3': 19, '4': 1, '5': 13, '10': 'rightScoreAddition'}, {'1': 'leftGoalInt', '3': 20, '4': 1, '5': 4, '10': 'leftGoalInt'}, {'1': 'rightGoalInt', '3': 21, '4': 1, '5': 4, '10': 'rightGoalInt'}, ], }; /// Descriptor for `Against`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List againstDescriptor = $convert.base64Decode( 'CgdBZ2FpbnN0EhoKCGxlZnROYW1lGAEgASgJUghsZWZ0TmFtZRIpCghsZWZ0TG9nbxgCIAEoCz' 'INLmRvdXlpbi5JbWFnZVIIbGVmdExvZ28SGgoIbGVmdEdvYWwYAyABKAlSCGxlZnRHb2FsEhwK' 'CXJpZ2h0TmFtZRgGIAEoCVIJcmlnaHROYW1lEisKCXJpZ2h0TG9nbxgHIAEoCzINLmRvdXlpbi' '5JbWFnZVIJcmlnaHRMb2dvEhwKCXJpZ2h0R29hbBgIIAEoCVIJcmlnaHRHb2FsEhwKCXRpbWVz' 'dGFtcBgLIAEoBFIJdGltZXN0YW1wEhgKB3ZlcnNpb24YDCABKARSB3ZlcnNpb24SHgoKbGVmdF' 'RlYW1JZBgNIAEoBFIKbGVmdFRlYW1JZBIgCgtyaWdodFRlYW1JZBgOIAEoBFILcmlnaHRUZWFt' 'SWQSLAoRZGlmZlNlaTJhYnNTZWNvbmQYDyABKARSEWRpZmZTZWkyYWJzU2Vjb25kEiYKDmZpbm' 'FsR29hbFN0YWdlGBAgASgNUg5maW5hbEdvYWxTdGFnZRIqChBjdXJyZW50R29hbFN0YWdlGBEg' 'ASgNUhBjdXJyZW50R29hbFN0YWdlEiwKEWxlZnRTY29yZUFkZGl0aW9uGBIgASgNUhFsZWZ0U2' 'NvcmVBZGRpdGlvbhIuChJyaWdodFNjb3JlQWRkaXRpb24YEyABKA1SEnJpZ2h0U2NvcmVBZGRp' 'dGlvbhIgCgtsZWZ0R29hbEludBgUIAEoBFILbGVmdEdvYWxJbnQSIgoMcmlnaHRHb2FsSW50GB' 'UgASgEUgxyaWdodEdvYWxJbnQ='); @$core.Deprecated('Use commonDescriptor instead') const Common$json = { '1': 'Common', '2': [ {'1': 'method', '3': 1, '4': 1, '5': 9, '10': 'method'}, {'1': 'msgId', '3': 2, '4': 1, '5': 4, '10': 'msgId'}, {'1': 'roomId', '3': 3, '4': 1, '5': 4, '10': 'roomId'}, {'1': 'createTime', '3': 4, '4': 1, '5': 4, '10': 'createTime'}, {'1': 'monitor', '3': 5, '4': 1, '5': 13, '10': 'monitor'}, {'1': 'isShowMsg', '3': 6, '4': 1, '5': 8, '10': 'isShowMsg'}, {'1': 'describe', '3': 7, '4': 1, '5': 9, '10': 'describe'}, {'1': 'foldType', '3': 9, '4': 1, '5': 4, '10': 'foldType'}, {'1': 'anchorFoldType', '3': 10, '4': 1, '5': 4, '10': 'anchorFoldType'}, {'1': 'priorityScore', '3': 11, '4': 1, '5': 4, '10': 'priorityScore'}, {'1': 'logId', '3': 12, '4': 1, '5': 9, '10': 'logId'}, {'1': 'msgProcessFilterK', '3': 13, '4': 1, '5': 9, '10': 'msgProcessFilterK'}, {'1': 'msgProcessFilterV', '3': 14, '4': 1, '5': 9, '10': 'msgProcessFilterV'}, {'1': 'user', '3': 15, '4': 1, '5': 11, '6': '.douyin.User', '10': 'user'}, {'1': 'anchorFoldTypeV2', '3': 17, '4': 1, '5': 4, '10': 'anchorFoldTypeV2'}, {'1': 'processAtSeiTimeMs', '3': 18, '4': 1, '5': 4, '10': 'processAtSeiTimeMs'}, {'1': 'randomDispatchMs', '3': 19, '4': 1, '5': 4, '10': 'randomDispatchMs'}, {'1': 'isDispatch', '3': 20, '4': 1, '5': 8, '10': 'isDispatch'}, {'1': 'channelId', '3': 21, '4': 1, '5': 4, '10': 'channelId'}, {'1': 'diffSei2absSecond', '3': 22, '4': 1, '5': 4, '10': 'diffSei2absSecond'}, {'1': 'anchorFoldDuration', '3': 23, '4': 1, '5': 4, '10': 'anchorFoldDuration'}, ], }; /// Descriptor for `Common`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List commonDescriptor = $convert.base64Decode( 'CgZDb21tb24SFgoGbWV0aG9kGAEgASgJUgZtZXRob2QSFAoFbXNnSWQYAiABKARSBW1zZ0lkEh' 'YKBnJvb21JZBgDIAEoBFIGcm9vbUlkEh4KCmNyZWF0ZVRpbWUYBCABKARSCmNyZWF0ZVRpbWUS' 'GAoHbW9uaXRvchgFIAEoDVIHbW9uaXRvchIcCglpc1Nob3dNc2cYBiABKAhSCWlzU2hvd01zZx' 'IaCghkZXNjcmliZRgHIAEoCVIIZGVzY3JpYmUSGgoIZm9sZFR5cGUYCSABKARSCGZvbGRUeXBl' 'EiYKDmFuY2hvckZvbGRUeXBlGAogASgEUg5hbmNob3JGb2xkVHlwZRIkCg1wcmlvcml0eVNjb3' 'JlGAsgASgEUg1wcmlvcml0eVNjb3JlEhQKBWxvZ0lkGAwgASgJUgVsb2dJZBIsChFtc2dQcm9j' 'ZXNzRmlsdGVySxgNIAEoCVIRbXNnUHJvY2Vzc0ZpbHRlcksSLAoRbXNnUHJvY2Vzc0ZpbHRlcl' 'YYDiABKAlSEW1zZ1Byb2Nlc3NGaWx0ZXJWEiAKBHVzZXIYDyABKAsyDC5kb3V5aW4uVXNlclIE' 'dXNlchIqChBhbmNob3JGb2xkVHlwZVYyGBEgASgEUhBhbmNob3JGb2xkVHlwZVYyEi4KEnByb2' 'Nlc3NBdFNlaVRpbWVNcxgSIAEoBFIScHJvY2Vzc0F0U2VpVGltZU1zEioKEHJhbmRvbURpc3Bh' 'dGNoTXMYEyABKARSEHJhbmRvbURpc3BhdGNoTXMSHgoKaXNEaXNwYXRjaBgUIAEoCFIKaXNEaX' 'NwYXRjaBIcCgljaGFubmVsSWQYFSABKARSCWNoYW5uZWxJZBIsChFkaWZmU2VpMmFic1NlY29u' 'ZBgWIAEoBFIRZGlmZlNlaTJhYnNTZWNvbmQSLgoSYW5jaG9yRm9sZER1cmF0aW9uGBcgASgEUh' 'JhbmNob3JGb2xkRHVyYXRpb24='); @$core.Deprecated('Use userDescriptor instead') const User$json = { '1': 'User', '2': [ {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'}, {'1': 'shortId', '3': 2, '4': 1, '5': 4, '10': 'shortId'}, {'1': 'nickName', '3': 3, '4': 1, '5': 9, '10': 'nickName'}, {'1': 'gender', '3': 4, '4': 1, '5': 13, '10': 'gender'}, {'1': 'Signature', '3': 5, '4': 1, '5': 9, '10': 'Signature'}, {'1': 'Level', '3': 6, '4': 1, '5': 13, '10': 'Level'}, {'1': 'Birthday', '3': 7, '4': 1, '5': 4, '10': 'Birthday'}, {'1': 'Telephone', '3': 8, '4': 1, '5': 9, '10': 'Telephone'}, {'1': 'AvatarThumb', '3': 9, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'AvatarThumb'}, {'1': 'AvatarMedium', '3': 10, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'AvatarMedium'}, {'1': 'AvatarLarge', '3': 11, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'AvatarLarge'}, {'1': 'Verified', '3': 12, '4': 1, '5': 8, '10': 'Verified'}, {'1': 'Experience', '3': 13, '4': 1, '5': 13, '10': 'Experience'}, {'1': 'city', '3': 14, '4': 1, '5': 9, '10': 'city'}, {'1': 'Status', '3': 15, '4': 1, '5': 5, '10': 'Status'}, {'1': 'CreateTime', '3': 16, '4': 1, '5': 4, '10': 'CreateTime'}, {'1': 'ModifyTime', '3': 17, '4': 1, '5': 4, '10': 'ModifyTime'}, {'1': 'Secret', '3': 18, '4': 1, '5': 13, '10': 'Secret'}, {'1': 'ShareQrcodeUri', '3': 19, '4': 1, '5': 9, '10': 'ShareQrcodeUri'}, {'1': 'IncomeSharePercent', '3': 20, '4': 1, '5': 13, '10': 'IncomeSharePercent'}, {'1': 'BadgeImageList', '3': 21, '4': 3, '5': 11, '6': '.douyin.Image', '10': 'BadgeImageList'}, {'1': 'FollowInfo', '3': 22, '4': 1, '5': 11, '6': '.douyin.FollowInfo', '10': 'FollowInfo'}, {'1': 'SpecialId', '3': 26, '4': 1, '5': 9, '10': 'SpecialId'}, {'1': 'AvatarBorder', '3': 27, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'AvatarBorder'}, {'1': 'Medal', '3': 28, '4': 1, '5': 11, '6': '.douyin.Image', '10': 'Medal'}, {'1': 'RealTimeIconsList', '3': 29, '4': 3, '5': 11, '6': '.douyin.Image', '10': 'RealTimeIconsList'}, {'1': 'displayId', '3': 38, '4': 1, '5': 9, '10': 'displayId'}, {'1': 'secUid', '3': 46, '4': 1, '5': 9, '10': 'secUid'}, {'1': 'fanTicketCount', '3': 1022, '4': 1, '5': 4, '10': 'fanTicketCount'}, {'1': 'idStr', '3': 1028, '4': 1, '5': 9, '10': 'idStr'}, {'1': 'ageRange', '3': 1045, '4': 1, '5': 13, '10': 'ageRange'}, ], }; /// Descriptor for `User`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List userDescriptor = $convert.base64Decode( 'CgRVc2VyEg4KAmlkGAEgASgEUgJpZBIYCgdzaG9ydElkGAIgASgEUgdzaG9ydElkEhoKCG5pY2' 'tOYW1lGAMgASgJUghuaWNrTmFtZRIWCgZnZW5kZXIYBCABKA1SBmdlbmRlchIcCglTaWduYXR1' 'cmUYBSABKAlSCVNpZ25hdHVyZRIUCgVMZXZlbBgGIAEoDVIFTGV2ZWwSGgoIQmlydGhkYXkYBy' 'ABKARSCEJpcnRoZGF5EhwKCVRlbGVwaG9uZRgIIAEoCVIJVGVsZXBob25lEi8KC0F2YXRhclRo' 'dW1iGAkgASgLMg0uZG91eWluLkltYWdlUgtBdmF0YXJUaHVtYhIxCgxBdmF0YXJNZWRpdW0YCi' 'ABKAsyDS5kb3V5aW4uSW1hZ2VSDEF2YXRhck1lZGl1bRIvCgtBdmF0YXJMYXJnZRgLIAEoCzIN' 'LmRvdXlpbi5JbWFnZVILQXZhdGFyTGFyZ2USGgoIVmVyaWZpZWQYDCABKAhSCFZlcmlmaWVkEh' '4KCkV4cGVyaWVuY2UYDSABKA1SCkV4cGVyaWVuY2USEgoEY2l0eRgOIAEoCVIEY2l0eRIWCgZT' 'dGF0dXMYDyABKAVSBlN0YXR1cxIeCgpDcmVhdGVUaW1lGBAgASgEUgpDcmVhdGVUaW1lEh4KCk' '1vZGlmeVRpbWUYESABKARSCk1vZGlmeVRpbWUSFgoGU2VjcmV0GBIgASgNUgZTZWNyZXQSJgoO' 'U2hhcmVRcmNvZGVVcmkYEyABKAlSDlNoYXJlUXJjb2RlVXJpEi4KEkluY29tZVNoYXJlUGVyY2' 'VudBgUIAEoDVISSW5jb21lU2hhcmVQZXJjZW50EjUKDkJhZGdlSW1hZ2VMaXN0GBUgAygLMg0u' 'ZG91eWluLkltYWdlUg5CYWRnZUltYWdlTGlzdBIyCgpGb2xsb3dJbmZvGBYgASgLMhIuZG91eW' 'luLkZvbGxvd0luZm9SCkZvbGxvd0luZm8SHAoJU3BlY2lhbElkGBogASgJUglTcGVjaWFsSWQS' 'MQoMQXZhdGFyQm9yZGVyGBsgASgLMg0uZG91eWluLkltYWdlUgxBdmF0YXJCb3JkZXISIwoFTW' 'VkYWwYHCABKAsyDS5kb3V5aW4uSW1hZ2VSBU1lZGFsEjsKEVJlYWxUaW1lSWNvbnNMaXN0GB0g' 'AygLMg0uZG91eWluLkltYWdlUhFSZWFsVGltZUljb25zTGlzdBIcCglkaXNwbGF5SWQYJiABKA' 'lSCWRpc3BsYXlJZBIWCgZzZWNVaWQYLiABKAlSBnNlY1VpZBInCg5mYW5UaWNrZXRDb3VudBj+' 'ByABKARSDmZhblRpY2tldENvdW50EhUKBWlkU3RyGIQIIAEoCVIFaWRTdHISGwoIYWdlUmFuZ2' 'UYlQggASgNUghhZ2VSYW5nZQ=='); @$core.Deprecated('Use followInfoDescriptor instead') const FollowInfo$json = { '1': 'FollowInfo', '2': [ {'1': 'followingCount', '3': 1, '4': 1, '5': 4, '10': 'followingCount'}, {'1': 'followerCount', '3': 2, '4': 1, '5': 4, '10': 'followerCount'}, {'1': 'followStatus', '3': 3, '4': 1, '5': 4, '10': 'followStatus'}, {'1': 'pushStatus', '3': 4, '4': 1, '5': 4, '10': 'pushStatus'}, {'1': 'remarkName', '3': 5, '4': 1, '5': 9, '10': 'remarkName'}, {'1': 'followerCountStr', '3': 6, '4': 1, '5': 9, '10': 'followerCountStr'}, {'1': 'followingCountStr', '3': 7, '4': 1, '5': 9, '10': 'followingCountStr'}, ], }; /// Descriptor for `FollowInfo`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List followInfoDescriptor = $convert.base64Decode( 'CgpGb2xsb3dJbmZvEiYKDmZvbGxvd2luZ0NvdW50GAEgASgEUg5mb2xsb3dpbmdDb3VudBIkCg' '1mb2xsb3dlckNvdW50GAIgASgEUg1mb2xsb3dlckNvdW50EiIKDGZvbGxvd1N0YXR1cxgDIAEo' 'BFIMZm9sbG93U3RhdHVzEh4KCnB1c2hTdGF0dXMYBCABKARSCnB1c2hTdGF0dXMSHgoKcmVtYX' 'JrTmFtZRgFIAEoCVIKcmVtYXJrTmFtZRIqChBmb2xsb3dlckNvdW50U3RyGAYgASgJUhBmb2xs' 'b3dlckNvdW50U3RyEiwKEWZvbGxvd2luZ0NvdW50U3RyGAcgASgJUhFmb2xsb3dpbmdDb3VudF' 'N0cg=='); @$core.Deprecated('Use imageDescriptor instead') const Image$json = { '1': 'Image', '2': [ {'1': 'urlListList', '3': 1, '4': 3, '5': 9, '10': 'urlListList'}, {'1': 'uri', '3': 2, '4': 1, '5': 9, '10': 'uri'}, {'1': 'height', '3': 3, '4': 1, '5': 4, '10': 'height'}, {'1': 'width', '3': 4, '4': 1, '5': 4, '10': 'width'}, {'1': 'avgColor', '3': 5, '4': 1, '5': 9, '10': 'avgColor'}, {'1': 'imageType', '3': 6, '4': 1, '5': 13, '10': 'imageType'}, {'1': 'openWebUrl', '3': 7, '4': 1, '5': 9, '10': 'openWebUrl'}, {'1': 'content', '3': 8, '4': 1, '5': 11, '6': '.douyin.ImageContent', '10': 'content'}, {'1': 'isAnimated', '3': 9, '4': 1, '5': 8, '10': 'isAnimated'}, {'1': 'FlexSettingList', '3': 10, '4': 1, '5': 11, '6': '.douyin.NinePatchSetting', '10': 'FlexSettingList'}, {'1': 'TextSettingList', '3': 11, '4': 1, '5': 11, '6': '.douyin.NinePatchSetting', '10': 'TextSettingList'}, ], }; /// Descriptor for `Image`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List imageDescriptor = $convert.base64Decode( 'CgVJbWFnZRIgCgt1cmxMaXN0TGlzdBgBIAMoCVILdXJsTGlzdExpc3QSEAoDdXJpGAIgASgJUg' 'N1cmkSFgoGaGVpZ2h0GAMgASgEUgZoZWlnaHQSFAoFd2lkdGgYBCABKARSBXdpZHRoEhoKCGF2' 'Z0NvbG9yGAUgASgJUghhdmdDb2xvchIcCglpbWFnZVR5cGUYBiABKA1SCWltYWdlVHlwZRIeCg' 'pvcGVuV2ViVXJsGAcgASgJUgpvcGVuV2ViVXJsEi4KB2NvbnRlbnQYCCABKAsyFC5kb3V5aW4u' 'SW1hZ2VDb250ZW50Ugdjb250ZW50Eh4KCmlzQW5pbWF0ZWQYCSABKAhSCmlzQW5pbWF0ZWQSQg' 'oPRmxleFNldHRpbmdMaXN0GAogASgLMhguZG91eWluLk5pbmVQYXRjaFNldHRpbmdSD0ZsZXhT' 'ZXR0aW5nTGlzdBJCCg9UZXh0U2V0dGluZ0xpc3QYCyABKAsyGC5kb3V5aW4uTmluZVBhdGNoU2' 'V0dGluZ1IPVGV4dFNldHRpbmdMaXN0'); @$core.Deprecated('Use ninePatchSettingDescriptor instead') const NinePatchSetting$json = { '1': 'NinePatchSetting', '2': [ {'1': 'settingListList', '3': 1, '4': 3, '5': 9, '10': 'settingListList'}, ], }; /// Descriptor for `NinePatchSetting`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List ninePatchSettingDescriptor = $convert.base64Decode( 'ChBOaW5lUGF0Y2hTZXR0aW5nEigKD3NldHRpbmdMaXN0TGlzdBgBIAMoCVIPc2V0dGluZ0xpc3' 'RMaXN0'); @$core.Deprecated('Use imageContentDescriptor instead') const ImageContent$json = { '1': 'ImageContent', '2': [ {'1': 'name', '3': 1, '4': 1, '5': 9, '10': 'name'}, {'1': 'fontColor', '3': 2, '4': 1, '5': 9, '10': 'fontColor'}, {'1': 'level', '3': 3, '4': 1, '5': 4, '10': 'level'}, {'1': 'alternativeText', '3': 4, '4': 1, '5': 9, '10': 'alternativeText'}, ], }; /// Descriptor for `ImageContent`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List imageContentDescriptor = $convert.base64Decode( 'CgxJbWFnZUNvbnRlbnQSEgoEbmFtZRgBIAEoCVIEbmFtZRIcCglmb250Q29sb3IYAiABKAlSCW' 'ZvbnRDb2xvchIUCgVsZXZlbBgDIAEoBFIFbGV2ZWwSKAoPYWx0ZXJuYXRpdmVUZXh0GAQgASgJ' 'Ug9hbHRlcm5hdGl2ZVRleHQ='); @$core.Deprecated('Use pushFrameDescriptor instead') const PushFrame$json = { '1': 'PushFrame', '2': [ {'1': 'seqId', '3': 1, '4': 1, '5': 4, '10': 'seqId'}, {'1': 'logId', '3': 2, '4': 1, '5': 4, '10': 'logId'}, {'1': 'service', '3': 3, '4': 1, '5': 4, '10': 'service'}, {'1': 'method', '3': 4, '4': 1, '5': 4, '10': 'method'}, {'1': 'headersList', '3': 5, '4': 3, '5': 11, '6': '.douyin.HeadersList', '10': 'headersList'}, {'1': 'payloadEncoding', '3': 6, '4': 1, '5': 9, '10': 'payloadEncoding'}, {'1': 'payloadType', '3': 7, '4': 1, '5': 9, '10': 'payloadType'}, {'1': 'payload', '3': 8, '4': 1, '5': 12, '10': 'payload'}, ], }; /// Descriptor for `PushFrame`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List pushFrameDescriptor = $convert.base64Decode( 'CglQdXNoRnJhbWUSFAoFc2VxSWQYASABKARSBXNlcUlkEhQKBWxvZ0lkGAIgASgEUgVsb2dJZB' 'IYCgdzZXJ2aWNlGAMgASgEUgdzZXJ2aWNlEhYKBm1ldGhvZBgEIAEoBFIGbWV0aG9kEjUKC2hl' 'YWRlcnNMaXN0GAUgAygLMhMuZG91eWluLkhlYWRlcnNMaXN0UgtoZWFkZXJzTGlzdBIoCg9wYX' 'lsb2FkRW5jb2RpbmcYBiABKAlSD3BheWxvYWRFbmNvZGluZxIgCgtwYXlsb2FkVHlwZRgHIAEo' 'CVILcGF5bG9hZFR5cGUSGAoHcGF5bG9hZBgIIAEoDFIHcGF5bG9hZA=='); @$core.Deprecated('Use kkDescriptor instead') const kk$json = { '1': 'kk', '2': [ {'1': 'k', '3': 14, '4': 1, '5': 13, '10': 'k'}, ], }; /// Descriptor for `kk`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List kkDescriptor = $convert.base64Decode( 'CgJraxIMCgFrGA4gASgNUgFr'); @$core.Deprecated('Use sendMessageBodyDescriptor instead') const SendMessageBody$json = { '1': 'SendMessageBody', '2': [ {'1': 'conversationId', '3': 1, '4': 1, '5': 9, '10': 'conversationId'}, {'1': 'conversationType', '3': 2, '4': 1, '5': 13, '10': 'conversationType'}, {'1': 'conversationShortId', '3': 3, '4': 1, '5': 4, '10': 'conversationShortId'}, {'1': 'content', '3': 4, '4': 1, '5': 9, '10': 'content'}, {'1': 'ext', '3': 5, '4': 3, '5': 11, '6': '.douyin.ExtList', '10': 'ext'}, {'1': 'messageType', '3': 6, '4': 1, '5': 13, '10': 'messageType'}, {'1': 'ticket', '3': 7, '4': 1, '5': 9, '10': 'ticket'}, {'1': 'clientMessageId', '3': 8, '4': 1, '5': 9, '10': 'clientMessageId'}, ], }; /// Descriptor for `SendMessageBody`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List sendMessageBodyDescriptor = $convert.base64Decode( 'Cg9TZW5kTWVzc2FnZUJvZHkSJgoOY29udmVyc2F0aW9uSWQYASABKAlSDmNvbnZlcnNhdGlvbk' 'lkEioKEGNvbnZlcnNhdGlvblR5cGUYAiABKA1SEGNvbnZlcnNhdGlvblR5cGUSMAoTY29udmVy' 'c2F0aW9uU2hvcnRJZBgDIAEoBFITY29udmVyc2F0aW9uU2hvcnRJZBIYCgdjb250ZW50GAQgAS' 'gJUgdjb250ZW50EiEKA2V4dBgFIAMoCzIPLmRvdXlpbi5FeHRMaXN0UgNleHQSIAoLbWVzc2Fn' 'ZVR5cGUYBiABKA1SC21lc3NhZ2VUeXBlEhYKBnRpY2tldBgHIAEoCVIGdGlja2V0EigKD2NsaW' 'VudE1lc3NhZ2VJZBgIIAEoCVIPY2xpZW50TWVzc2FnZUlk'); @$core.Deprecated('Use extListDescriptor instead') const ExtList$json = { '1': 'ExtList', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, ], }; /// Descriptor for `ExtList`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List extListDescriptor = $convert.base64Decode( 'CgdFeHRMaXN0EhAKA2tleRgBIAEoCVIDa2V5EhQKBXZhbHVlGAIgASgJUgV2YWx1ZQ=='); @$core.Deprecated('Use rspDescriptor instead') const Rsp$json = { '1': 'Rsp', '2': [ {'1': 'a', '3': 1, '4': 1, '5': 5, '10': 'a'}, {'1': 'b', '3': 2, '4': 1, '5': 5, '10': 'b'}, {'1': 'c', '3': 3, '4': 1, '5': 5, '10': 'c'}, {'1': 'd', '3': 4, '4': 1, '5': 9, '10': 'd'}, {'1': 'e', '3': 5, '4': 1, '5': 5, '10': 'e'}, {'1': 'f', '3': 6, '4': 1, '5': 11, '6': '.douyin.Rsp.F', '10': 'f'}, {'1': 'g', '3': 7, '4': 1, '5': 9, '10': 'g'}, {'1': 'h', '3': 10, '4': 1, '5': 4, '10': 'h'}, {'1': 'i', '3': 11, '4': 1, '5': 4, '10': 'i'}, {'1': 'j', '3': 13, '4': 1, '5': 4, '10': 'j'}, ], '3': [Rsp_F$json], }; @$core.Deprecated('Use rspDescriptor instead') const Rsp_F$json = { '1': 'F', '2': [ {'1': 'q1', '3': 1, '4': 1, '5': 4, '10': 'q1'}, {'1': 'q3', '3': 3, '4': 1, '5': 4, '10': 'q3'}, {'1': 'q4', '3': 4, '4': 1, '5': 9, '10': 'q4'}, {'1': 'q5', '3': 5, '4': 1, '5': 4, '10': 'q5'}, ], }; /// Descriptor for `Rsp`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List rspDescriptor = $convert.base64Decode( 'CgNSc3ASDAoBYRgBIAEoBVIBYRIMCgFiGAIgASgFUgFiEgwKAWMYAyABKAVSAWMSDAoBZBgEIA' 'EoCVIBZBIMCgFlGAUgASgFUgFlEhsKAWYYBiABKAsyDS5kb3V5aW4uUnNwLkZSAWYSDAoBZxgH' 'IAEoCVIBZxIMCgFoGAogASgEUgFoEgwKAWkYCyABKARSAWkSDAoBahgNIAEoBFIBahpDCgFGEg' '4KAnExGAEgASgEUgJxMRIOCgJxMxgDIAEoBFICcTMSDgoCcTQYBCABKAlSAnE0Eg4KAnE1GAUg' 'ASgEUgJxNQ=='); @$core.Deprecated('Use preMessageDescriptor instead') const PreMessage$json = { '1': 'PreMessage', '2': [ {'1': 'cmd', '3': 1, '4': 1, '5': 13, '10': 'cmd'}, {'1': 'sequenceId', '3': 2, '4': 1, '5': 13, '10': 'sequenceId'}, {'1': 'sdkVersion', '3': 3, '4': 1, '5': 9, '10': 'sdkVersion'}, {'1': 'token', '3': 4, '4': 1, '5': 9, '10': 'token'}, {'1': 'refer', '3': 5, '4': 1, '5': 13, '10': 'refer'}, {'1': 'inboxType', '3': 6, '4': 1, '5': 13, '10': 'inboxType'}, {'1': 'buildNumber', '3': 7, '4': 1, '5': 9, '10': 'buildNumber'}, {'1': 'sendMessageBody', '3': 8, '4': 1, '5': 11, '6': '.douyin.SendMessageBody', '10': 'sendMessageBody'}, {'1': 'aa', '3': 9, '4': 1, '5': 9, '10': 'aa'}, {'1': 'devicePlatform', '3': 11, '4': 1, '5': 9, '10': 'devicePlatform'}, {'1': 'headers', '3': 15, '4': 3, '5': 11, '6': '.douyin.HeadersList', '10': 'headers'}, {'1': 'authType', '3': 18, '4': 1, '5': 13, '10': 'authType'}, {'1': 'biz', '3': 21, '4': 1, '5': 9, '10': 'biz'}, {'1': 'access', '3': 22, '4': 1, '5': 9, '10': 'access'}, ], }; /// Descriptor for `PreMessage`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List preMessageDescriptor = $convert.base64Decode( 'CgpQcmVNZXNzYWdlEhAKA2NtZBgBIAEoDVIDY21kEh4KCnNlcXVlbmNlSWQYAiABKA1SCnNlcX' 'VlbmNlSWQSHgoKc2RrVmVyc2lvbhgDIAEoCVIKc2RrVmVyc2lvbhIUCgV0b2tlbhgEIAEoCVIF' 'dG9rZW4SFAoFcmVmZXIYBSABKA1SBXJlZmVyEhwKCWluYm94VHlwZRgGIAEoDVIJaW5ib3hUeX' 'BlEiAKC2J1aWxkTnVtYmVyGAcgASgJUgtidWlsZE51bWJlchJBCg9zZW5kTWVzc2FnZUJvZHkY' 'CCABKAsyFy5kb3V5aW4uU2VuZE1lc3NhZ2VCb2R5Ug9zZW5kTWVzc2FnZUJvZHkSDgoCYWEYCS' 'ABKAlSAmFhEiYKDmRldmljZVBsYXRmb3JtGAsgASgJUg5kZXZpY2VQbGF0Zm9ybRItCgdoZWFk' 'ZXJzGA8gAygLMhMuZG91eWluLkhlYWRlcnNMaXN0UgdoZWFkZXJzEhoKCGF1dGhUeXBlGBIgAS' 'gNUghhdXRoVHlwZRIQCgNiaXoYFSABKAlSA2JpehIWCgZhY2Nlc3MYFiABKAlSBmFjY2Vzcw=='); @$core.Deprecated('Use headersListDescriptor instead') const HeadersList$json = { '1': 'HeadersList', '2': [ {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'}, {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'}, ], }; /// Descriptor for `HeadersList`. Decode as a `google.protobuf.DescriptorProto`. final $typed_data.Uint8List headersListDescriptor = $convert.base64Decode( 'CgtIZWFkZXJzTGlzdBIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1ZRgCIAEoCVIFdmFsdWU='); ================================================ FILE: simple_live_core/lib/src/danmaku/proto/douyin.proto ================================================ syntax = "proto3"; package douyin; message Response { repeated Message messagesList = 1; string cursor = 2; uint64 fetchInterval = 3; uint64 now = 4; string internalExt = 5; uint32 fetchType = 6; map routeParams = 7; uint64 heartbeatDuration = 8; bool needAck = 9; string pushServer = 10; string liveCursor = 11; bool historyNoMore = 12; } message Message{ string method = 1; bytes payload = 2; int64 msgId = 3; int32 msgType = 4; int64 offset = 5; bool needWrdsStore = 6; int64 wrdsVersion = 7; string wrdsSubKey = 8; } // 聊天 message ChatMessage { Common common = 1; User user = 2; string content = 3; bool visibleToSender = 4; Image backgroundImage = 5; string fullScreenTextColor = 6; Image backgroundImageV2 = 7; PublicAreaCommon publicAreaCommon = 8; Image giftImage = 9; uint64 agreeMsgId = 11; uint32 priorityLevel = 12; LandscapeAreaCommon landscapeAreaCommon = 13; uint64 eventTime = 15; bool sendReview = 16; bool fromIntercom = 17; bool intercomHideUserCard = 18; // repeated chatTagsList = 19; string chatBy = 20; uint32 individualChatPriority = 21; Text rtfContent = 22; } message LandscapeAreaCommon { bool showHead = 1; bool showNickname = 2; bool showFontColor = 3; repeated string colorValueList = 4; repeated CommentTypeTag commentTypeTagsList = 5; } message RoomUserSeqMessage { Common common = 1; repeated RoomUserSeqMessageContributor ranksList = 2; int64 total = 3; string popStr = 4; repeated RoomUserSeqMessageContributor seatsList = 5; int64 popularity = 6; int64 totalUser = 7; string totalUserStr = 8; string totalStr = 9; string onlineUserForAnchor = 10; string totalPvForAnchor = 11; string upRightStatsStr = 12; string upRightStatsStrComplete = 13; } message CommonTextMessage { Common common = 1; User user = 2; string scene = 3; } message UpdateFanTicketMessage { Common common = 1; string roomFanTicketCountText = 2; uint64 roomFanTicketCount = 3; bool forceUpdate = 4; } message RoomUserSeqMessageContributor { uint64 score = 1; User user = 2; uint64 rank = 3; uint64 delta = 4; bool isHidden = 5; string scoreDescription = 6; string exactlyScore = 7; } // 礼物消息 message GiftMessage { Common common = 1; uint64 giftId = 2; uint64 fanTicketCount = 3; uint64 groupCount = 4; uint64 repeatCount = 5; uint64 comboCount = 6; User user = 7; User toUser = 8; uint32 repeatEnd = 9; TextEffect textEffect = 10; uint64 groupId = 11; uint64 incomeTaskgifts = 12; uint64 roomFanTicketCount = 13; GiftIMPriority priority = 14; GiftStruct gift = 15; string logId = 16; uint64 sendType = 17; PublicAreaCommon publicAreaCommon = 18; Text trayDisplayText = 19; uint64 bannedDisplayEffects = 20; // GiftTrayInfo trayInfo = 21; // AssetEffectMixInfo assetEffectMixInfo = 22; bool displayForSelf = 25; string interactGiftInfo = 26; string diyItemInfo = 27; repeated uint64 minAssetSetList = 28; uint64 totalCount = 29; uint32 clientGiftSource = 30; // AnchorGiftData anchorGift = 31; repeated uint64 toUserIdsList = 32; uint64 sendTime = 33; uint64 forceDisplayEffects = 34; string traceId = 35; uint64 effectDisplayTs = 36; } message GiftStruct { Image image = 1; string describe = 2; bool notify = 3; uint64 duration = 4; uint64 id = 5; // GiftStructFansClubInfo fansclubInfo = 6; bool forLinkmic = 7; bool doodle = 8; bool forFansclub = 9; bool combo = 10; uint32 type = 11; uint32 diamondCount = 12; bool isDisplayedOnPanel = 13; uint64 primaryEffectId = 14; Image giftLabelIcon = 15; string name = 16; string region = 17; string manual = 18; bool forCustom = 19; // specialEffectsMap = 20; Image icon = 21; uint32 actionType = 22; // fixme 后面的就不写了还有几十个属性 } message GiftIMPriority { repeated uint64 queueSizesList = 1; uint64 selfQueuePriority = 2; uint64 priority = 3; } message TextEffect { TextEffectDetail portrait = 1; TextEffectDetail landscape = 2; } message TextEffectDetail { Text text = 1; uint32 textFontSize = 2; Image background = 3; uint32 start = 4; uint32 duration = 5; uint32 x = 6; uint32 y = 7; uint32 width = 8; uint32 height = 9; uint32 shadowDx = 10; uint32 shadowDy = 11; uint32 shadowRadius = 12; string shadowColor = 13; string strokeColor = 14; uint32 strokeWidth = 15; } // 成员消息 message MemberMessage { Common common = 1; User user = 2; uint64 memberCount = 3; User operator = 4; bool isSetToAdmin = 5; bool isTopUser = 6; uint64 rankScore = 7; uint64 topUserNo = 8; uint64 enterType = 9; uint64 action = 10; string actionDescription = 11; uint64 userId = 12; EffectConfig effectConfig = 13; string popStr = 14; EffectConfig enterEffectConfig = 15; Image backgroundImage = 16; Image backgroundImageV2 = 17; Text anchorDisplayText = 18; PublicAreaCommon publicAreaCommon = 19; uint64 userEnterTipType = 20; uint64 anchorEnterTipType = 21; } message PublicAreaCommon { Image userLabel = 1; uint64 userConsumeInRoom = 2; uint64 userSendGiftCntInRoom = 3; } message EffectConfig { uint64 type = 1; Image icon = 2; uint64 avatarPos = 3; Text text = 4; Image textIcon = 5; uint32 stayTime = 6; uint64 animAssetId = 7; Image badge = 8; repeated uint64 flexSettingArrayList = 9; Image textIconOverlay = 10; Image animatedBadge = 11; bool hasSweepLight = 12; repeated uint64 textFlexSettingArrayList = 13; uint64 centerAnimAssetId = 14; Image dynamicImage = 15; map extraMap = 16; uint64 mp4AnimAssetId = 17; uint64 priority = 18; uint64 maxWaitTime = 19; string dressId = 20; uint64 alignment = 21; uint64 alignmentOffset = 22; } message Text { string key = 1; string defaultPatter = 2; TextFormat defaultFormat = 3; repeated TextPiece piecesList = 4; } message TextPiece { bool type = 1; TextFormat format = 2; string stringValue = 3; TextPieceUser userValue = 4; TextPieceGift giftValue = 5; TextPieceHeart heartValue = 6; TextPiecePatternRef patternRefValue = 7; TextPieceImage imageValue = 8; } message TextPieceImage { Image image = 1; float scalingRate = 2; } message TextPiecePatternRef { string key = 1; string defaultPattern = 2; } message TextPieceHeart { string color = 1; } message TextPieceGift { uint64 giftId = 1; PatternRef nameRef = 2; } message PatternRef { string key = 1; string defaultPattern = 2; } message TextPieceUser { User user = 1; bool withColon = 2; } message TextFormat { string color = 1; bool bold = 2; bool italic = 3; uint32 weight = 4; uint32 italicAngle = 5; uint32 fontSize = 6; bool useHeighLightColor = 7; bool useRemoteClor = 8; } // 点赞 message LikeMessage { Common common = 1; uint64 count = 2; uint64 total = 3; uint64 color = 4; User user = 5; string icon = 6; DoubleLikeDetail doubleLikeDetail = 7; DisplayControlInfo displayControlInfo = 8; uint64 linkmicGuestUid = 9; string scene = 10; PicoDisplayInfo picoDisplayInfo = 11; } message SocialMessage { Common common = 1; User user = 2; uint64 shareType = 3; uint64 action = 4; string shareTarget = 5; uint64 followCount = 6; PublicAreaCommon publicAreaCommon = 7; } message PicoDisplayInfo { uint64 comboSumCount = 1; string emoji = 2; Image emojiIcon = 3; string emojiText = 4; } message DoubleLikeDetail { bool doubleFlag = 1; uint32 seqId = 2; uint32 renewalsNum = 3; uint32 triggersNum = 4; } message DisplayControlInfo { bool showText = 1; bool showIcons = 2; } message EpisodeChatMessage { Message common = 1; User user = 2; string content = 3; bool visibleToSende = 4; // BackgroundImage backgroundImage = 5; // PublicAreaCommon publicAreaCommon = 6; Image giftImage = 7; uint64 agreeMsgId = 8; repeated string colorValueList = 9; } message MatchAgainstScoreMessage { Common common = 1; Against against = 2; uint32 matchStatus = 3; uint32 displayStatus = 4; } message Against { string leftName = 1; Image leftLogo = 2; string leftGoal = 3; // LeftPlayersList leftPlayersList = 4; // LeftGoalStageDetail leftGoalStageDetail = 5; string rightName = 6; Image rightLogo = 7; string rightGoal = 8; // RightPlayersList rightPlayersList = 9; // RightGoalStageDetail rightGoalStageDetail = 10; uint64 timestamp = 11; uint64 version = 12; uint64 leftTeamId = 13; uint64 rightTeamId = 14; uint64 diffSei2absSecond = 15; uint32 finalGoalStage = 16; uint32 currentGoalStage =17; uint32 leftScoreAddition =18; uint32 rightScoreAddition =19; uint64 leftGoalInt = 20; uint64 rightGoalInt = 21; } message Common { string method = 1; uint64 msgId = 2; uint64 roomId = 3; uint64 createTime = 4; uint32 monitor = 5; bool isShowMsg = 6; string describe = 7; // DisplayText displayText = 8; uint64 foldType = 9; uint64 anchorFoldType = 10; uint64 priorityScore = 11; string logId = 12; string msgProcessFilterK = 13; string msgProcessFilterV = 14; User user = 15; // Room room = 16; uint64 anchorFoldTypeV2 = 17; uint64 processAtSeiTimeMs = 18; uint64 randomDispatchMs = 19; bool isDispatch = 20; uint64 channelId = 21; uint64 diffSei2absSecond = 22; uint64 anchorFoldDuration = 23; } message User { uint64 id = 1; uint64 shortId = 2; string nickName = 3; uint32 gender = 4; string Signature = 5; uint32 Level = 6; uint64 Birthday = 7; string Telephone = 8; Image AvatarThumb = 9; Image AvatarMedium = 10; Image AvatarLarge = 11; bool Verified = 12; uint32 Experience = 13; string city = 14; int32 Status = 15; uint64 CreateTime = 16; uint64 ModifyTime = 17; uint32 Secret = 18; string ShareQrcodeUri = 19; uint32 IncomeSharePercent = 20; repeated Image BadgeImageList = 21; FollowInfo FollowInfo = 22; // PayGrade PayGrade = 23; // FansClub FansClub = 24; // Border Border = 25; string SpecialId = 26; Image AvatarBorder = 27; Image Medal = 28; repeated Image RealTimeIconsList = 29; string displayId = 38; string secUid = 46; uint64 fanTicketCount = 1022; string idStr = 1028; uint32 ageRange = 1045; } message FollowInfo { uint64 followingCount = 1; uint64 followerCount = 2; uint64 followStatus = 3; uint64 pushStatus = 4; string remarkName = 5; string followerCountStr = 6; string followingCountStr = 7; } message Image { repeated string urlListList = 1; string uri = 2; uint64 height = 3; uint64 width = 4; string avgColor = 5; uint32 imageType = 6; string openWebUrl = 7; ImageContent content = 8; bool isAnimated = 9; NinePatchSetting FlexSettingList = 10; NinePatchSetting TextSettingList = 11; } message NinePatchSetting { repeated string settingListList = 1; } message ImageContent { string name = 1; string fontColor = 2; uint64 level = 3; string alternativeText = 4; } message PushFrame { uint64 seqId = 1; uint64 logId = 2; uint64 service = 3; uint64 method = 4; repeated HeadersList headersList = 5; string payloadEncoding = 6; string payloadType = 7; bytes payload = 8; } message kk { uint32 k=14; } message SendMessageBody { string conversationId = 1; uint32 conversationType = 2; uint64 conversationShortId = 3; string content = 4; repeated ExtList ext = 5; uint32 messageType = 6; string ticket = 7; string clientMessageId = 8; } message ExtList { string key = 1; string value = 2; } message Rsp{ int32 a = 1; int32 b = 2; int32 c = 3; string d = 4; int32 e = 5; message F { uint64 q1 = 1; uint64 q3 = 3; string q4 = 4; uint64 q5 = 5; } F f = 6; string g = 7; uint64 h = 10; uint64 i = 11; uint64 j = 13; } message PreMessage { uint32 cmd = 1; uint32 sequenceId = 2; string sdkVersion = 3; string token = 4; uint32 refer = 5; uint32 inboxType = 6; string buildNumber = 7; SendMessageBody sendMessageBody = 8; // 字段名待定 string aa = 9; string devicePlatform = 11; repeated HeadersList headers = 15; uint32 authType = 18; string biz = 21; string access = 22; } message HeadersList { string key = 1; string value = 2; } enum CommentTypeTag { COMMENTTYPETAGUNKNOWN = 0; COMMENTTYPETAGSTAR = 1; } ================================================ FILE: simple_live_core/lib/src/douyin_site.dart ================================================ import 'dart:convert'; import 'dart:math'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_core/src/common/convert_helper.dart'; import 'package:simple_live_core/src/common/http_client.dart'; import 'package:simple_live_core/src/scripts/douyin_sign.dart'; class DouyinSite implements LiveSite { @override String id = "douyin"; @override String name = "抖音直播"; @override LiveDanmaku getDanmaku() => DouyinDanmaku(); /// 使用 QQBrowser User-Agent(参考 DouyinLiveRecorder) static const String kDefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.567.400 QQBrowser/19.7.6764.400"; static const String kDefaultReferer = "https://live.douyin.com"; static const String kDefaultAuthority = "live.douyin.com"; /// 默认 Cookie - 只需要 ttwid 字段即可获取所有画质(包括蓝光) /// 经过测试验证,LOGIN_STATUS=1 等其他字段都是可选的 static const String kDefaultCookie = "ttwid=1%7CB1qls3GdnZhUov9o2NxOMxxYS2ff6OSvEWbv0ytbES4%7C1680522049%7C280d802d6d478e3e78d0c807f7c487e7ffec0ae4e5fdd6a0fe74c3c6af149511"; /// 用户设置的 cookie String cookie = ""; void _logDebug(String msg) { // 同时使用 print 和 CoreLog 确保日志输出 print("[Douyin] $msg"); CoreLog.d("[Douyin] $msg"); } Map headers = { "Authority": kDefaultAuthority, "Referer": kDefaultReferer, "User-Agent": kDefaultUserAgent, }; Future> getRequestHeaders() async { try { // 如果用户已设置 cookie,直接使用用户的 cookie if (cookie.isNotEmpty) { headers["cookie"] = cookie; return headers; } // 使用默认的 ttwid cookie(只需要 ttwid 即可获取所有画质) headers["cookie"] = kDefaultCookie; return headers; } catch (e) { CoreLog.error(e); if (!(headers["cookie"]?.toString().isNotEmpty ?? false)) { headers["cookie"] = kDefaultCookie; } return headers; } } @override Future> getCategores() async { List categories = []; var result = await HttpClient.instance.getText( "https://live.douyin.com/", queryParameters: {}, header: await getRequestHeaders(), ); var renderData = RegExp( r'\{\\"pathname\\":\\"\/\\",\\"categoryData.*?\]\\n', ).firstMatch(result)?.group(0) ?? ""; var renderDataJson = json.decode( renderData .trim() .replaceAll('\\"', '"') .replaceAll(r"\\", r"\") .replaceAll(']\\n', ""), ); for (var item in renderDataJson["categoryData"]) { List subs = []; var id = '${item["partition"]["id_str"]},${item["partition"]["type"]}'; for (var subItem in item["sub_partition"]) { var subCategory = LiveSubCategory( id: '${subItem["partition"]["id_str"]},${subItem["partition"]["type"]}', name: asT(subItem["partition"]["title"]) ?? "", parentId: id, pic: "", ); subs.add(subCategory); } var category = LiveCategory( children: subs, id: id, name: asT(item["partition"]["title"]) ?? "", ); subs.insert( 0, LiveSubCategory( id: category.id, name: category.name, parentId: category.id, pic: "", ), ); categories.add(category); } return categories; } @override Future getCategoryRooms( LiveSubCategory category, { int page = 1, }) async { var ids = category.id.split(','); var partitionId = ids[0]; var partitionType = ids[1]; String serverUrl = "https://live.douyin.com/webcast/web/partition/detail/room/v2/"; var uri = Uri.parse(serverUrl).replace( scheme: "https", port: 443, queryParameters: { "aid": '6383', "app_name": "douyin_web", "live_id": '1', "device_platform": "web", "language": "zh-CN", "enter_from": "link_share", "cookie_enabled": "true", "screen_width": "1980", "screen_height": "1080", "browser_language": "zh-CN", "browser_platform": "Win32", "browser_name": "Edge", "browser_version": "125.0.0.0", "browser_online": "true", "count": '15', "offset": ((page - 1) * 15).toString(), "partition": partitionId, "partition_type": partitionType, "req_from": '2', }, ); var requestUrl = DouyinSign.getAbogusUrl(uri.toString(), kDefaultUserAgent); var result = await HttpClient.instance.getJson( requestUrl, header: await getRequestHeaders(), ); var hasMore = (result["data"]["data"] as List).length >= 15; var items = []; for (var item in result["data"]["data"]) { var roomItem = LiveRoomItem( roomId: item["web_rid"], title: item["room"]["title"].toString(), cover: item["room"]["cover"]["url_list"][0].toString(), userName: item["room"]["owner"]["nickname"].toString(), online: int.tryParse( item["room"]["room_view_stats"]["display_value"].toString(), ) ?? 0, ); items.add(roomItem); } return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future getRecommendRooms({int page = 1}) async { String serverUrl = "https://live.douyin.com/webcast/web/partition/detail/room/v2/"; var uri = Uri.parse(serverUrl).replace( scheme: "https", port: 443, queryParameters: { "aid": '6383', "app_name": "douyin_web", "live_id": '1', "device_platform": "web", "language": "zh-CN", "enter_from": "link_share", "cookie_enabled": "true", "screen_width": "1980", "screen_height": "1080", "browser_language": "zh-CN", "browser_platform": "Win32", "browser_name": "Edge", "browser_version": "125.0.0.0", "browser_online": "true", "count": '15', "offset": ((page - 1) * 15).toString(), "partition": '720', "partition_type": '1', "req_from": '2', }, ); var requestUrl = DouyinSign.getAbogusUrl(uri.toString(), kDefaultUserAgent); var result = await HttpClient.instance.getJson( requestUrl, header: await getRequestHeaders(), ); var hasMore = (result["data"]["data"] as List).length >= 15; var items = []; for (var item in result["data"]["data"]) { var roomItem = LiveRoomItem( roomId: item["web_rid"], title: item["room"]["title"].toString(), cover: item["room"]["cover"]["url_list"][0].toString(), userName: item["room"]["owner"]["nickname"].toString(), online: int.tryParse( item["room"]["room_view_stats"]["display_value"].toString(), ) ?? 0, ); items.add(roomItem); } return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future getRoomDetail({required String roomId}) async { // 有两种roomId,一种是webRid,一种是roomId // roomId是一次性的,用户每次重新开播都会生成一个新的roomId // roomId一般长度为19位,例如:7376429659866598196 // webRid是固定的,用户每次开播都是同一个webRid // webRid一般长度为11-12位,例如:416144012050 // 这里简单进行判断,如果roomId长度小于15,则认为是webRid if (roomId.length <= 16) { var webRid = roomId; return await getRoomDetailByWebRid(webRid); } return await getRoomDetailByRoomId(roomId); } /// 通过roomId获取直播间信息 /// - [roomId] 直播间ID /// - 返回直播间信息 Future getRoomDetailByRoomId(String roomId) async { // 读取房间信息 var roomData = await _getRoomDataByRoomId(roomId); // 通过房间信息获取WebRid var webRid = roomData["data"]["room"]["owner"]["web_rid"].toString(); // 读取用户唯一ID,用于弹幕连接 // 似乎这个参数不是必须的,先随机生成一个 //var userUniqueId = await _getUserUniqueId(webRid); var userUniqueId = generateRandomNumber(12).toString(); var room = roomData["data"]["room"]; var owner = room["owner"]; var status = asT(room["status"]) ?? 0; // roomId是一次性的,用户每次重新开播都会生成一个新的roomId // 所以如果roomId对应的直播间状态不是直播中,就通过webRid获取直播间信息 if (status == 4) { var result = await getRoomDetailByWebRid(webRid); return result; } var roomStatus = status == 2; // 主要是为了获取cookie,用于弹幕websocket连接 var headers = await getRequestHeaders(); return LiveRoomDetail( roomId: webRid, title: room["title"].toString(), cover: roomStatus ? room["cover"]["url_list"][0].toString() : "", userName: owner["nickname"].toString(), userAvatar: owner["avatar_thumb"]["url_list"][0].toString(), online: roomStatus ? asT(room["room_view_stats"]["display_value"]) ?? 0 : 0, status: roomStatus, url: "https://live.douyin.com/$webRid", introduction: owner["signature"].toString(), notice: "", danmakuData: DouyinDanmakuArgs( webRid: webRid, roomId: roomId, userId: userUniqueId, cookie: headers["cookie"], ), data: room["stream_url"], ); } /// 通过WebRid获取直播间信息 /// - [webRid] 直播间RID /// - 返回直播间信息 Future getRoomDetailByWebRid(String webRid) async { try { var result = await _getRoomDetailByWebRidApi(webRid); return result; } catch (e) { CoreLog.error(e); } return await _getRoomDetailByWebRidHtml(webRid); } /// 通过WebRid访问直播间API,从API中获取直播间信息 /// - [webRid] 直播间RID /// - 返回直播间信息 Future _getRoomDetailByWebRidApi(String webRid) async { // 读取房间信息 var data = await _getRoomDataByApi(webRid); var roomData = data["data"][0]; var userData = data["user"]; var roomId = roomData["id_str"].toString(); // 读取用户唯一ID,用于弹幕连接 // 似乎这个参数不是必须的,先随机生成一个 //var userUniqueId = await _getUserUniqueId(webRid); var userUniqueId = generateRandomNumber(12).toString(); var owner = roomData["owner"]; var roomStatus = (asT(roomData["status"]) ?? 0) == 2; // 主要是为了获取cookie,用于弹幕websocket连接 var headers = await getRequestHeaders(); return LiveRoomDetail( roomId: webRid, title: roomData["title"].toString(), cover: roomStatus ? roomData["cover"]["url_list"][0].toString() : "", userName: roomStatus ? owner["nickname"].toString() : userData["nickname"].toString(), userAvatar: roomStatus ? owner["avatar_thumb"]["url_list"][0].toString() : userData["avatar_thumb"]["url_list"][0].toString(), online: roomStatus ? asT(roomData["room_view_stats"]["display_value"]) ?? 0 : 0, status: roomStatus, url: "https://live.douyin.com/$webRid", introduction: owner?["signature"]?.toString() ?? "", notice: "", danmakuData: DouyinDanmakuArgs( webRid: webRid, roomId: roomId, userId: userUniqueId, cookie: headers["cookie"], ), data: roomStatus ? roomData["stream_url"] : {}, ); } /// 通过WebRid访问直播间网页,从网页HTML中获取直播间信息 /// - [webRid] 直播间RID /// - 返回直播间信息 Future _getRoomDetailByWebRidHtml(String webRid) async { var roomData = await _getRoomDataByHtml(webRid); var roomId = roomData["roomStore"]["roomInfo"]["room"]["id_str"].toString(); var userUniqueId = roomData["userStore"]["odin"]["user_unique_id"] .toString(); var room = roomData["roomStore"]["roomInfo"]["room"]; var owner = room["owner"]; var anchor = roomData["roomStore"]["roomInfo"]["anchor"]; var roomStatus = (asT(room["status"]) ?? 0) == 2; // 主要是为了获取cookie,用于弹幕websocket连接 var headers = await getRequestHeaders(); return LiveRoomDetail( roomId: webRid, title: room["title"].toString(), cover: roomStatus ? room["cover"]["url_list"][0].toString() : "", userName: roomStatus ? owner["nickname"].toString() : anchor["nickname"].toString(), userAvatar: roomStatus ? owner["avatar_thumb"]["url_list"][0].toString() : anchor["avatar_thumb"]["url_list"][0].toString(), online: roomStatus ? asT(room["room_view_stats"]["display_value"]) ?? 0 : 0, status: roomStatus, url: "https://live.douyin.com/$webRid", introduction: owner?["signature"]?.toString() ?? "", notice: "", danmakuData: DouyinDanmakuArgs( webRid: webRid, roomId: roomId, userId: userUniqueId, cookie: headers["cookie"], ), data: roomStatus ? room["stream_url"] : {}, ); } /// 读取用户的唯一ID /// - [webRid] 直播间RID // ignore: unused_element Future _getUserUniqueId(String webRid) async { try { var webInfo = await _getRoomDataByHtml(webRid); return webInfo["userStore"]["odin"]["user_unique_id"].toString(); } catch (e) { return generateRandomNumber(12).toString(); } } /// 进入直播间前需要先获取cookie /// - [webRid] 直播间RID Future _getWebCookie(String webRid) async { var headResp = await HttpClient.instance.head( "https://live.douyin.com/$webRid", header: headers, ); var dyCookie = ""; headResp.headers["set-cookie"]?.forEach((element) { var cookie = element.split(";")[0]; if (cookie.contains("ttwid")) { dyCookie += "$cookie;"; } if (cookie.contains("__ac_nonce")) { dyCookie += "$cookie;"; } if (cookie.contains("msToken")) { dyCookie += "$cookie;"; } }); return dyCookie; } /// 通过webRid获取直播间Web信息 /// - [webRid] 直播间RID Future _getRoomDataByHtml(String webRid) async { var dyCookie = await _getWebCookie(webRid); var result = await HttpClient.instance.getText( "https://live.douyin.com/$webRid", queryParameters: {}, header: { "Authority": kDefaultAuthority, "Referer": kDefaultReferer, "Cookie": dyCookie, "User-Agent": kDefaultUserAgent, }, ); var renderData = RegExp( r'\{\\"state\\":\{\\"appStore.*?\]\\n', ).firstMatch(result)?.group(0) ?? ""; var str = renderData .trim() .replaceAll('\\"', '"') .replaceAll(r"\\", r"\") .replaceAll(']\\n', ""); var renderDataJson = json.decode(str); return renderDataJson["state"]; } /// 通过webRid获取直播间Web信息 /// - [webRid] 直播间RID Future _getRoomDataByApi(String webRid) async { String serverUrl = "https://live.douyin.com/webcast/room/web/enter/"; // 提前获取 headers var requestHeader = await getRequestHeaders(); // 使用动态 Referer(包含房间号,参考 DouyinLiveRecorder) requestHeader["Referer"] = "https://live.douyin.com/$webRid"; var uri = Uri.parse(serverUrl).replace( scheme: "https", port: 443, queryParameters: { "aid": '6383', "app_name": "douyin_web", "live_id": '1', "device_platform": "web", "language": "zh-CN", "browser_language": "zh-CN", "browser_platform": "Win32", "browser_name": "Chrome", "browser_version": "125.0.0.0", "web_rid": webRid, "msToken": "", }, ); var requestUrl = DouyinSign.getAbogusUrl(uri.toString(), kDefaultUserAgent); var result = await HttpClient.instance.getJson( requestUrl, header: requestHeader, ); if (result is! Map) { throw Exception("抖音接口返回格式异常"); } return result["data"]; } /// 通过roomId获取直播间信息 /// - [roomId] 直播间ID Future _getRoomDataByRoomId(String roomId) async { var result = await HttpClient.instance.getJson( 'https://webcast.amemv.com/webcast/room/reflow/info/', queryParameters: { "type_id": 0, "live_id": 1, "room_id": roomId, "sec_user_id": "", "version_code": "99.99.99", "app_id": 6383, }, header: await getRequestHeaders(), ); return result; } @override Future> getPlayQualites({ required LiveRoomDetail detail, }) async { List qualities = []; try { var liveCoreData = detail.data["live_core_sdk_data"]; if (liveCoreData == null) { return qualities; } var pullData = liveCoreData["pull_data"]; if (pullData == null) { return qualities; } var options = pullData["options"]; var qulityList = options?["qualities"]; var streamData = pullData["stream_data"]?.toString() ?? ""; if (!streamData.startsWith('{')) { var flvList = (detail.data["flv_pull_url"] as Map).values .cast() .toList(); var hlsList = (detail.data["hls_pull_url_map"] as Map).values .cast() .toList(); for (var quality in qulityList) { int level = quality["level"]; List urls = []; var flvIndex = flvList.length - level; if (flvIndex >= 0 && flvIndex < flvList.length) { urls.add(flvList[flvIndex]); } var hlsIndex = hlsList.length - level; if (hlsIndex >= 0 && hlsIndex < hlsList.length) { urls.add(hlsList[hlsIndex]); } var qualityItem = LivePlayQuality( quality: quality["name"], sort: level, data: urls, ); if (urls.isNotEmpty) { qualities.add(qualityItem); } } } else { var qualityData = json.decode(streamData)["data"] as Map; for (var quality in qulityList) { List urls = []; var flvUrl = qualityData[quality["sdk_key"]]?["main"]?["flv"] ?.toString(); if (flvUrl != null && flvUrl.isNotEmpty) { urls.add(flvUrl); } var hlsUrl = qualityData[quality["sdk_key"]]?["main"]?["hls"] ?.toString(); if (hlsUrl != null && hlsUrl.isNotEmpty) { urls.add(hlsUrl); } var qualityItem = LivePlayQuality( quality: quality["name"], sort: quality["level"], data: urls, ); if (urls.isNotEmpty) { qualities.add(qualityItem); } } } } catch (e, stackTrace) { CoreLog.error(e); CoreLog.error(stackTrace); } // var qualityData = json.decode( // detail.data["live_core_sdk_data"]["pull_data"]["stream_data"])["data"]; qualities.sort((a, b) => b.sort.compareTo(a.sort)); _logDebug("获取到的画质列表: ${qualities.map((q) => q.quality).toList()}"); return qualities; } @override Future getPlayUrls({ required LiveRoomDetail detail, required LivePlayQuality quality, }) async { // 返回列表的副本,防止外部 clear() 影响原始数据 return LivePlayUrl(urls: List.from(quality.data)); } @override Future searchRooms( String keyword, { int page = 1, }) async { String serverUrl = "https://www.douyin.com/aweme/v1/web/live/search/"; var uri = Uri.parse(serverUrl).replace( scheme: "https", port: 443, queryParameters: { "device_platform": "webapp", "aid": "6383", "channel": "channel_pc_web", "search_channel": "aweme_live", "keyword": keyword, "search_source": "switch_tab", "query_correct_type": "1", "is_filter_search": "0", "from_group_id": "", "offset": ((page - 1) * 10).toString(), "count": "10", "pc_client_type": "1", "version_code": "170400", "version_name": "17.4.0", "cookie_enabled": "true", "screen_width": "1980", "screen_height": "1080", "browser_language": "zh-CN", "browser_platform": "Win32", "browser_name": "Edge", "browser_version": "125.0.0.0", "browser_online": "true", "engine_name": "Blink", "engine_version": "125.0.0.0", "os_name": "Windows", "os_version": "10", "cpu_core_num": "12", "device_memory": "8", "platform": "PC", "downlink": "10", "effective_type": "4g", "round_trip_time": "100", "webid": "7382872326016435738", }, ); //var requlestUrl = await getAbogusUrl(uri.toString()); var requlestUrl = uri.toString(); var headResp = await HttpClient.instance.head( 'https://live.douyin.com', header: headers, ); var dyCookie = ""; headResp.headers["set-cookie"]?.forEach((element) { var cookie = element.split(";")[0]; if (cookie.contains("ttwid")) { dyCookie += "$cookie;"; } if (cookie.contains("__ac_nonce")) { dyCookie += "$cookie;"; } }); var result = await HttpClient.instance.getJson( requlestUrl, queryParameters: {}, header: { "Authority": 'www.douyin.com', 'accept': 'application/json, text/plain, */*', 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8', 'cookie': dyCookie, 'priority': 'u=1, i', 'referer': 'https://www.douyin.com/search/${Uri.encodeComponent(keyword)}?type=live', 'sec-ch-ua': '"Microsoft Edge";v="125", "Chromium";v="125", "Not.A/Brand";v="24"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': kDefaultUserAgent, }, ); if (result == "" || result == 'blocked') { throw Exception("抖音直播搜索被限制,请稍后再试"); } var items = []; for (var item in result["data"] ?? []) { var itemData = json.decode(item["lives"]["rawdata"].toString()); var roomItem = LiveRoomItem( roomId: itemData["owner"]["web_rid"].toString(), title: itemData["title"].toString(), cover: itemData["cover"]["url_list"][0].toString(), userName: itemData["owner"]["nickname"].toString(), online: int.tryParse(itemData["stats"]["total_user"].toString()) ?? 0, ); items.add(roomItem); } return LiveSearchRoomResult(hasMore: items.length >= 10, items: items); } @override Future searchAnchors( String keyword, { int page = 1, }) async { throw Exception("抖音暂不支持搜索主播,请直接搜索直播间"); } @override Future getLiveStatus({required String roomId}) async { var result = await getRoomDetail(roomId: roomId); return result.status; } @override Future> getSuperChatMessage({ required String roomId, }) { return Future.value([]); } //生成指定长度的16进制随机字符串 String generateRandomString(int length) { var random = Random.secure(); var values = List.generate(length, (i) => random.nextInt(16)); StringBuffer stringBuffer = StringBuffer(); for (var item in values) { stringBuffer.write(item.toRadixString(16)); } return stringBuffer.toString(); } // 生成随机的数字 int generateRandomNumber(int length) { var random = Random.secure(); var values = List.generate(length, (i) => random.nextInt(10)); StringBuffer stringBuffer = StringBuffer(); for (var item in values) { stringBuffer.write(item); } return int.tryParse(stringBuffer.toString()) ?? Random().nextInt(1000000000); } } ================================================ FILE: simple_live_core/lib/src/douyu_site.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'dart:math'; import 'package:simple_live_core/src/common/http_client.dart'; import 'package:simple_live_core/src/danmaku/douyu_danmaku.dart'; import 'package:simple_live_core/src/interface/live_danmaku.dart'; import 'package:simple_live_core/src/interface/live_site.dart'; import 'package:simple_live_core/src/model/live_anchor_item.dart'; import 'package:simple_live_core/src/model/live_category.dart'; import 'package:simple_live_core/src/model/live_message.dart'; import 'package:simple_live_core/src/model/live_play_url.dart'; import 'package:simple_live_core/src/model/live_room_item.dart'; import 'package:simple_live_core/src/model/live_search_result.dart'; import 'package:simple_live_core/src/model/live_room_detail.dart'; import 'package:simple_live_core/src/model/live_play_quality.dart'; import 'package:simple_live_core/src/model/live_category_result.dart'; import 'package:html_unescape/html_unescape.dart'; import 'package:simple_live_core/src/scripts/douyu_sign.dart'; class DouyuSite implements LiveSite { @override String id = "douyu"; @override String name = "斗鱼直播"; @override LiveDanmaku getDanmaku() => DouyuDanmaku(); @override Future> getCategores() async { List categories = []; var result = await HttpClient.instance.getJson( "https://m.douyu.com/api/cate/list", ); var subCateList = result["data"]["cate2Info"] as List; for (var item in result["data"]["cate1Info"]) { var cate1Id = item["cate1Id"]; var cate1Name = item["cate1Name"]; List subCategories = []; subCateList.where((x) => x["cate1Id"] == cate1Id).forEach((element) { subCategories.add( LiveSubCategory( pic: element["icon"], id: element["cate2Id"].toString(), parentId: cate1Id.toString(), name: element["cate2Name"].toString(), ), ); }); categories.add( LiveCategory( id: cate1Id.toString(), name: cate1Name.toString(), children: subCategories, ), ); } // 根据ID排序 categories.sort((a, b) => int.parse(a.id).compareTo(int.parse(b.id))); return categories; } @override Future getCategoryRooms( LiveSubCategory category, { int page = 1, }) async { var result = await HttpClient.instance.getJson( "https://www.douyu.com/gapi/rkc/directory/mixList/2_${category.id}/$page", queryParameters: {}, ); var items = []; for (var item in result['data']['rl']) { if (item["type"] != 1) { continue; } var roomItem = LiveRoomItem( cover: item['rs16'].toString(), online: item['ol'], roomId: item['rid'].toString(), title: item['rn'].toString(), userName: item['nn'].toString(), ); items.add(roomItem); } var hasMore = page < result['data']['pgcnt']; return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future> getPlayQualites({ required LiveRoomDetail detail, }) async { var data = detail.data.toString(); data += "&cdn=&rate=-1&ver=Douyu_223061205&iar=1&ive=1&hevc=0&fa=0"; List qualities = []; var result = await HttpClient.instance.postJson( "https://www.douyu.com/lapi/live/getH5Play/${detail.roomId}", data: data, formUrlEncoded: true, ); var cdns = []; for (var item in result["data"]["cdnsWithName"]) { cdns.add(item["cdn"].toString()); } // 如果cdn以scdn开头,将其放到最后 cdns.sort((a, b) { if (a.startsWith("scdn") && !b.startsWith("scdn")) { return 1; } else if (!a.startsWith("scdn") && b.startsWith("scdn")) { return -1; } return 0; }); for (var item in result["data"]["multirates"]) { qualities.add( LivePlayQuality( quality: item["name"].toString(), data: DouyuPlayData(item["rate"], cdns), ), ); } return qualities; } @override Future getPlayUrls({ required LiveRoomDetail detail, required LivePlayQuality quality, }) async { var args = detail.data.toString(); var data = quality.data as DouyuPlayData; List urls = []; for (var item in data.cdns) { var url = await getPlayUrl(detail.roomId, args, data.rate, item); if (url.isNotEmpty) { urls.add(url); } } return LivePlayUrl(urls: urls); } Future getPlayUrl( String roomId, String args, int rate, String cdn, ) async { args += "&cdn=$cdn&rate=$rate"; var result = await HttpClient.instance.postJson( "https://www.douyu.com/lapi/live/getH5Play/$roomId", data: args, header: { 'referer': 'https://www.douyu.com/$roomId', 'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43", }, formUrlEncoded: true, ); return "${result["data"]["rtmp_url"]}/${HtmlUnescape().convert(result["data"]["rtmp_live"].toString())}"; } @override Future getRecommendRooms({int page = 1}) async { var result = await HttpClient.instance.getJson( "https://www.douyu.com/japi/weblist/apinc/allpage/6/$page", queryParameters: {}, ); var items = []; for (var item in result['data']['rl']) { if (item["type"] != 1) { continue; } var roomItem = LiveRoomItem( cover: item['rs16'].toString(), online: item['ol'], roomId: item['rid'].toString(), title: item['rn'].toString(), userName: item['nn'].toString(), ); items.add(roomItem); } var hasMore = page < result['data']['pgcnt']; return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future getRoomDetail({required String roomId}) async { Map roomInfo = await _getRoomInfo(roomId); Map h5RoomInfo = await HttpClient.instance.getJson( "https://www.douyu.com/swf_api/h5room/$roomId", queryParameters: {}, header: { 'referer': 'https://www.douyu.com/$roomId', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43', }, ); String? showTime = h5RoomInfo["data"]?["show_time"]?.toString(); var jsEncResult = await HttpClient.instance.getText( "https://www.douyu.com/swf_api/homeH5Enc?rids=$roomId", queryParameters: {}, header: { 'referer': 'https://www.douyu.com/$roomId', 'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43", }, ); var crptext = json.decode(jsEncResult)["data"]["room$roomId"].toString(); if (showTime != null && showTime.isNotEmpty) { try { int startTimeStamp = int.parse(showTime); int currentTimeStamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; int durationInSeconds = currentTimeStamp - startTimeStamp; int hours = durationInSeconds ~/ 3600; int minutes = (durationInSeconds % 3600) ~/ 60; int seconds = durationInSeconds % 60; String formattedDuration = '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; print('斗鱼直播间 $roomId 开播时长: $formattedDuration'); } catch (e) { print('计算开播时长出错: $e'); } } return LiveRoomDetail( cover: roomInfo["room_pic"].toString(), online: int.tryParse(roomInfo["room_biz_all"]["hot"].toString()) ?? 0, roomId: roomInfo["room_id"].toString(), title: roomInfo["room_name"].toString(), userName: roomInfo["owner_name"].toString(), userAvatar: roomInfo["owner_avatar"].toString(), introduction: roomInfo["show_details"].toString(), notice: "", status: roomInfo["show_status"] == 1 && roomInfo["videoLoop"] != 1, danmakuData: roomInfo["room_id"].toString(), data: DouyuSign.getSign(crptext, roomInfo["room_id"].toString()), url: "https://www.douyu.com/$roomId", isRecord: roomInfo["videoLoop"] == 1, showTime: showTime, ); } @override Future searchRooms( String keyword, { int page = 1, }) async { var did = generateRandomString(32); var result = await HttpClient.instance.getJson( "https://www.douyu.com/japi/search/api/searchShow", queryParameters: {"kw": keyword, "page": page, "pageSize": 20}, header: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.51', 'referer': 'https://www.douyu.com/search/', 'Cookie': 'dy_did=$did;acf_did=$did', }, ); if (result['error'] != 0) { throw Exception(result['msg']); } var items = []; for (var item in result["data"]["relateShow"]) { var roomItem = LiveRoomItem( roomId: item["rid"].toString(), title: item["roomName"].toString(), cover: item["roomSrc"].toString(), userName: item["nickName"].toString(), online: parseHotNum(item["hot"].toString()), ); items.add(roomItem); } var hasMore = result["data"]["relateShow"].isNotEmpty; return LiveSearchRoomResult(hasMore: hasMore, items: items); } Future _getRoomInfo(String roomId) async { var result = await HttpClient.instance.getJson( "https://www.douyu.com/betard/$roomId", queryParameters: {}, header: { 'referer': 'https://www.douyu.com/$roomId', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43', }, ); Map roomInfo; if (result is String) { roomInfo = json.decode(result)["room"]; } else { roomInfo = result["room"]; } return roomInfo; } //生成指定长度的16进制随机字符串 String generateRandomString(int length) { var random = Random.secure(); var values = List.generate(length, (i) => random.nextInt(16)); StringBuffer stringBuffer = StringBuffer(); for (var item in values) { stringBuffer.write(item.toRadixString(16)); } return stringBuffer.toString(); } @override Future searchAnchors( String keyword, { int page = 1, }) async { var did = generateRandomString(32); var result = await HttpClient.instance.getJson( "https://www.douyu.com/japi/search/api/searchUser", queryParameters: { "kw": keyword, "page": page, "pageSize": 20, "filterType": 1, }, header: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.51', 'referer': 'https://www.douyu.com/search/', 'Cookie': 'dy_did=$did;acf_did=$did', }, ); var items = []; for (var item in result["data"]["relateUser"]) { var liveStatus = (int.tryParse(item["anchorInfo"]["isLive"].toString()) ?? 0) == 1; var roomType = (int.tryParse(item["anchorInfo"]["roomType"].toString()) ?? 0); var roomItem = LiveAnchorItem( roomId: item["anchorInfo"]["rid"].toString(), avatar: item["anchorInfo"]["avatar"].toString(), userName: item["anchorInfo"]["nickName"].toString(), liveStatus: liveStatus && roomType == 0, ); items.add(roomItem); } var hasMore = result["data"]["relateUser"].isNotEmpty; return LiveSearchAnchorResult(hasMore: hasMore, items: items); } @override Future getLiveStatus({required String roomId}) async { var roomInfo = await _getRoomInfo(roomId); return roomInfo["show_status"] == 1 && roomInfo["videoLoop"] != 1; } int parseHotNum(String hn) { try { var num = double.parse(hn.replaceAll("万", "")); if (hn.contains("万")) { num *= 10000; } return num.round(); } catch (_) { return -999; } } @override Future> getSuperChatMessage({ required String roomId, }) { //尚不支持 return Future.value([]); } } class DouyuPlayData { final int rate; final List cdns; DouyuPlayData(this.rate, this.cdns); } ================================================ FILE: simple_live_core/lib/src/huya_site.dart ================================================ import 'dart:convert'; import 'dart:math'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_core/src/common/http_client.dart'; import 'package:crypto/crypto.dart'; import 'package:simple_live_core/src/model/tars/get_cdn_token_ex_req.dart'; import 'package:simple_live_core/src/model/tars/get_cdn_token_ex_resp.dart'; import 'package:simple_live_core/src/model/tars/get_cdn_token_req.dart'; import 'package:simple_live_core/src/model/tars/get_cdn_token_resp.dart'; import 'package:simple_live_core/src/model/tars/huya_user_id.dart'; import 'package:tars_dart/tars/net/base_tars_http.dart'; class HuyaSite implements LiveSite { static const baseUrl = "https://m.huya.com/"; final String kUserAgent = "Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36 Edg/117.0.0.0"; static const String HYSDK_UA = "HYSDK(Windows, 30000002)_APP(pc_exe&7060000&official)_SDK(trans&2.32.3.5646)"; static Map requestHeaders = { 'Origin': baseUrl, 'Referer': baseUrl, 'User-Agent': HYSDK_UA, }; final BaseTarsHttp tupClient = BaseTarsHttp("http://wup.huya.com", "liveui", headers: requestHeaders); String? playUserAgent; @override String id = "huya"; @override String name = "虎牙直播"; @override LiveDanmaku getDanmaku() => HuyaDanmaku(); @override Future> getCategores() async { List categories = [ LiveCategory(id: "1", name: "网游", children: []), LiveCategory(id: "2", name: "单机", children: []), LiveCategory(id: "8", name: "娱乐", children: []), LiveCategory(id: "3", name: "手游", children: []), ]; for (var item in categories) { var items = await getSubCategores(item.id); item.children.addAll(items); } return categories; } Future> getSubCategores(String id) async { var result = await HttpClient.instance.getJson( "https://live.cdn.huya.com/liveconfig/game/bussLive", queryParameters: { "bussType": id, }, ); List subs = []; for (var item in result["data"]) { var gid = ""; if (item["gid"] is Map) { gid = item["gid"]["value"].toString().split(",").first; } else if (item["gid"] is double) { gid = item["gid"].toInt().toString(); } else if (item["gid"] is int) { gid = item["gid"].toString(); } else { gid = item["gid"].toString(); } var subCategory = LiveSubCategory( id: gid, name: item["gameFullName"].toString(), parentId: id, pic: "https://huyaimg.msstatic.com/cdnimage/game/$gid-MS.jpg", ); subs.add(subCategory); } return subs; } @override Future getCategoryRooms(LiveSubCategory category, {int page = 1}) async { var resultText = await HttpClient.instance.getJson( "https://www.huya.com/cache.php", queryParameters: { "m": "LiveList", "do": "getLiveListByPage", "tagAll": 0, "gameId": category.id, "page": page }, ); var result = json.decode(resultText); var items = []; for (var item in result["data"]["datas"]) { var cover = item["screenshot"].toString(); if (!cover.contains("?")) { cover += "?x-oss-process=style/w338_h190&"; } var title = item["introduction"]?.toString() ?? ""; if (title.isEmpty) { title = item["roomName"]?.toString() ?? ""; } var roomItem = LiveRoomItem( roomId: item["profileRoom"].toString(), title: title, cover: cover, userName: item["nick"].toString(), online: int.tryParse(item["totalCount"].toString()) ?? 0, ); items.add(roomItem); } var hasMore = result["data"]["page"] < result["data"]["totalPage"]; return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future> getPlayQualites( {required LiveRoomDetail detail}) { List qualities = []; var urlData = detail.data as HuyaUrlDataModel; if (urlData.bitRates.isEmpty) { urlData.bitRates = [ HuyaBitRateModel( name: "原画", bitRate: 0, ), HuyaBitRateModel(name: "高清", bitRate: 2000), ]; } // if (urlData.lines.isEmpty) { // urlData.lines = [ // HuyaLineModel(line: "tx.flv.huya.com", lineType: HuyaLineType.flv,), // HuyaLineModel(line: "bd.flv.huya.com", lineType: HuyaLineType.flv), // HuyaLineModel(line: "al.flv.huya.com", lineType: HuyaLineType.flv), // HuyaLineModel(line: "hw.flv.huya.com", lineType: HuyaLineType.flv), // ]; // } //var url = getRealUrl(urlData.url); for (var item in urlData.bitRates) { // var urls = []; // for (var line in urlData.lines) { // var src = line.line; // src += "/${line.streamName}"; // if (line.lineType == HuyaLineType.flv) { // //src = src.replaceAll(".m3u8", ".flv"); // src += ".flv"; // } // if (line.lineType == HuyaLineType.hls) { // src += ".m3u8"; // } // var parms = processAnticode( // line.lineType == HuyaLineType.flv // ? line.flvAntiCode // : line.hlsAntiCode, // urlData.uid, // line.streamName, // ); // src += "?$parms"; // if (item.bitRate > 0) { // src += "&ratio=${item.bitRate}"; // } // urls.add(src); // } qualities.add(LivePlayQuality( data: { "urls": urlData.lines, "bitRate": item.bitRate, }, quality: item.name, )); } return Future.value(qualities); } // 每次访问播放虎牙都需要获取一次,不太合理,倾向于在客户端获取保存替换 Future getHuYaUA() async { if (playUserAgent != null) { return playUserAgent!; } try { var result = await HttpClient.instance.getJson( "https://github.iill.moe/xiaoyaocz/dart_simple_live/master/assets/play_config.json", queryParameters: { "ts": DateTime.now().millisecondsSinceEpoch, }, ); playUserAgent = json.decode(result)['huya']['user_agent']; } catch (e) { CoreLog.error(e); } return playUserAgent ?? HYSDK_UA; } @override Future getPlayUrls( {required LiveRoomDetail detail, required LivePlayQuality quality}) async { var ls = []; for (var element in quality.data["urls"]) { var line = element as HuyaLineModel; var url = await getPlayUrl(line, quality.data["bitRate"]); ls.add(url); } // 最新UA需要额外验证,此方法暂时弃用 // var ua = await getHuYaUA(); return LivePlayUrl( urls: ls, headers: {"user-agent": HYSDK_UA}, ); } Future getPlayUrl(HuyaLineModel line, int bitRate) async { var antiCode = await getCndTokenInfoEx(line.streamName); antiCode = buildAntiCode(line.streamName, line.presenterUid, antiCode); var url = '${line.line}/${line.streamName}.flv?${antiCode}&codec=264'; if (bitRate > 0) { url += "&ratio=$bitRate"; } return url; } // 构造 anticode, python转写 /// [stream] streamname [presenterUid] 用户id [antiCode] 页面anti /// /// return ture anticode String buildAntiCode(String stream, int presenterUid, String antiCode) { var mapAnti = Uri(query: antiCode).queryParametersAll; if (!mapAnti.containsKey("fm")) { return antiCode; } var ctype = mapAnti["ctype"]?.first ?? "huya_pc_exe"; var platformId = int.tryParse(mapAnti["t"]?.first ?? "0"); bool isWap = platformId == 103; var clacStartTime = DateTime.now().millisecondsSinceEpoch; CoreLog.i( "using $presenterUid | ctype-{$ctype} | platformId - {$platformId} | isWap - {$isWap} | $clacStartTime"); var seqId = presenterUid + clacStartTime; final secretHash = md5.convert(utf8.encode('$seqId|$ctype|$platformId')).toString(); final convertUid = rotl64(presenterUid); final calcUid = isWap ? presenterUid : convertUid; final fm = Uri.decodeComponent(mapAnti['fm']!.first); final secretPrefix = utf8.decode(base64.decode(fm)).split('_').first; var wsTime = mapAnti['wsTime']!.first; final secretStr = '${secretPrefix}_${calcUid}_${stream}_${secretHash}_$wsTime'; final wsSecret = md5.convert(utf8.encode(secretStr)).toString(); final rnd = Random(); final ct = ((int.parse(wsTime, radix: 16) + rnd.nextDouble()) * 1000).toInt(); final uuid = (((ct % 1e10) + rnd.nextDouble()) * 1e3 % 0xffffffff) .toInt() .toString(); final Map antiCodeRes = { 'wsSecret': wsSecret, 'wsTime': wsTime, 'seqid': seqId, 'ctype': ctype, 'ver': '1', 'fs': mapAnti['fs']!.first, 'fm': Uri.encodeComponent(mapAnti['fm']!.first), 't': platformId, }; if (isWap) { antiCodeRes.addAll({ 'uid': presenterUid, 'uuid': uuid, }); } else { antiCodeRes['u'] = convertUid; } return antiCodeRes.entries.map((e) => '${e.key}=${e.value}').join('&'); } /// return sFlvToken Future getCndTokenInfoEx(String stream) async { var func = "getCdnTokenInfoEx"; var tid = HuyaUserId(); tid.sHuYaUA = "pc_exe&7060000&official"; var tReq = GetCdnTokenExReq(); tReq.tId = tid; tReq.sStreamName = stream; var resp = await tupClient.tupRequest(func, tReq, GetCdnTokenExResp()); return resp.sFlvToken; } @override Future getRecommendRooms({int page = 1}) async { var resultText = await HttpClient.instance.getJson( "https://www.huya.com/cache.php", queryParameters: { "m": "LiveList", "do": "getLiveListByPage", "tagAll": 0, "page": page }, ); var result = json.decode(resultText); var items = []; for (var item in result["data"]["datas"]) { var cover = item["screenshot"].toString(); if (!cover.contains("?")) { cover += "?x-oss-process=style/w338_h190&"; } var title = item["introduction"]?.toString() ?? ""; if (title.isEmpty) { title = item["roomName"]?.toString() ?? ""; } var roomItem = LiveRoomItem( roomId: item["profileRoom"].toString(), title: title, cover: cover, userName: item["nick"].toString(), online: int.tryParse(item["totalCount"].toString()) ?? 0, ); items.add(roomItem); } var hasMore = result["data"]["page"] < result["data"]["totalPage"]; return LiveCategoryResult(hasMore: hasMore, items: items); } @override Future getRoomDetail({required String roomId}) async { var roomInfo = await _getRoomInfo(roomId); var tLiveInfo = roomInfo["roomInfo"]["tLiveInfo"]; var tProfileInfo = roomInfo["roomInfo"]["tProfileInfo"]; var title = tLiveInfo["sIntroduction"]?.toString() ?? ""; if (title.isEmpty) { title = tLiveInfo["sRoomName"]?.toString() ?? ""; } var huyaLines = []; var huyaBiterates = []; //读取可用线路 var lines = tLiveInfo["tLiveStreamInfo"]["vStreamInfo"]["value"]; for (var item in lines) { if ((item["sFlvUrl"]?.toString() ?? "").isNotEmpty) { huyaLines.add(HuyaLineModel( line: item["sFlvUrl"].toString(), lineType: HuyaLineType.flv, flvAntiCode: item["sFlvAntiCode"].toString(), hlsAntiCode: item["sHlsAntiCode"].toString(), streamName: item["sStreamName"].toString(), cdnType: item["sCdnType"].toString(), presenterUid: roomInfo["topSid"]??0, )); } } //清晰度 var biterates = tLiveInfo["tLiveStreamInfo"]["vBitRateInfo"]["value"]; for (var item in biterates) { var name = item["sDisplayName"].toString(); if (name.contains("HDR")) { continue; } huyaBiterates.add(HuyaBitRateModel( bitRate: item["iBitRate"], name: name, )); } var topSid = roomInfo["topSid"]; var subSid = roomInfo["subSid"]; return LiveRoomDetail( cover: tLiveInfo["sScreenshot"].toString(), online: tLiveInfo["lTotalCount"], roomId: tLiveInfo["lProfileRoom"].toString(), title: title, userName: tProfileInfo["sNick"].toString(), userAvatar: tProfileInfo["sAvatar180"].toString(), introduction: tLiveInfo["sIntroduction"].toString(), notice: roomInfo["welcomeText"].toString(), status: roomInfo["roomInfo"]["eLiveStatus"] == 2, data: HuyaUrlDataModel( url: "https:${utf8.decode(base64.decode(roomInfo["roomProfile"]["liveLineUrl"].toString()))}", lines: huyaLines, bitRates: huyaBiterates, uid: getUid(t: 13, e: 10), ), danmakuData: HuyaDanmakuArgs( ayyuid: tLiveInfo["lYyid"] ?? 0, topSid: topSid ?? 0, subSid: subSid ?? 0, ), url: "https://www.huya.com/$roomId", ); } Future _getRoomInfo(String roomId) async { var resultText = await HttpClient.instance.getText( "https://m.huya.com/$roomId", queryParameters: {}, header: { "user-agent": kUserAgent, }, ); var text = RegExp( r"window\.HNF_GLOBAL_INIT.=.\{[\s\S]*?\}[\s\S]*?", multiLine: false) .firstMatch(resultText) ?.group(0); var jsonText = text! .replaceAll(RegExp(r"window\.HNF_GLOBAL_INIT.=."), '') .replaceAll("", "") .replaceAllMapped(RegExp(r'function.*?\(.*?\).\{[\s\S]*?\}'), (match) { return '""'; }); var jsonObj = json.decode(jsonText); var topSid = int.tryParse( RegExp(r'lChannelId":([0-9]+)').firstMatch(resultText)?.group(1) ?? "0"); var subSid = int.tryParse( RegExp(r'lSubChannelId":([0-9]+)').firstMatch(resultText)?.group(1) ?? "0"); jsonObj["topSid"] = topSid; jsonObj["subSid"] = subSid; return jsonObj; } @override Future searchRooms(String keyword, {int page = 1}) async { var resultText = await HttpClient.instance.getJson( "https://search.cdn.huya.com/", queryParameters: { "m": "Search", "do": "getSearchContent", "q": keyword, "uid": 0, "v": 4, "typ": -5, "livestate": 0, "rows": 20, "start": (page - 1) * 20, }, ); var result = json.decode(resultText); var items = []; for (var item in result["response"]["3"]["docs"]) { var cover = item["game_screenshot"].toString(); if (!cover.contains("?")) { cover += "?x-oss-process=style/w338_h190&"; } var title = item["game_introduction"]?.toString() ?? ""; if (title.isEmpty) { title = item["game_roomName"]?.toString() ?? ""; } var roomItem = LiveRoomItem( roomId: item["room_id"].toString(), title: title, cover: cover, userName: item["game_nick"].toString(), online: int.tryParse(item["game_total_count"].toString()) ?? 0, ); items.add(roomItem); } var hasMore = result["response"]["3"]["numFound"] > (page * 20); return LiveSearchRoomResult(hasMore: hasMore, items: items); } @override Future searchAnchors(String keyword, {int page = 1}) async { var resultText = await HttpClient.instance.getJson( "https://search.cdn.huya.com/", queryParameters: { "m": "Search", "do": "getSearchContent", "q": keyword, "uid": 0, "v": 1, "typ": -5, "livestate": 0, "rows": 20, "start": (page - 1) * 20, }, ); var result = json.decode(resultText); var items = []; for (var item in result["response"]["1"]["docs"]) { var anchorItem = LiveAnchorItem( roomId: item["room_id"].toString(), avatar: item["game_avatarUrl180"].toString(), userName: item["game_nick"].toString(), liveStatus: item["gameLiveOn"], ); items.add(anchorItem); } var hasMore = result["response"]["1"]["numFound"] > (page * 20); return LiveSearchAnchorResult(hasMore: hasMore, items: items); } @override Future getLiveStatus({required String roomId}) async { var roomInfo = await _getRoomInfo(roomId); return roomInfo["roomInfo"]["eLiveStatus"] == 2; } /// 匿名登录获取uid Future getAnonymousUid() async { var result = await HttpClient.instance.postJson( "https://udblgn.huya.com/web/anonymousLogin", data: { "appId": 5002, "byPass": 3, "context": "", "version": "2.4", "data": {} }, header: { "user-agent": kUserAgent, }, ); return result["data"]["uid"].toString(); } int rotl64(int t) { final low = t & 0xFFFFFFFF; final rotatedLow = ((low << 8) | (low >> 24)) & 0xFFFFFFFF; final high = t & ~0xFFFFFFFF; return high | rotatedLow; } String getUUid() { var currentTime = DateTime.now().millisecondsSinceEpoch; var randomValue = Random().nextInt(4294967295); var result = (currentTime % 10000000000 * 1000 + randomValue) % 4294967295; return result.toString(); } String getUid({int? t, int? e}) { var n = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" .split(""); var o = List.filled(36, ''); if (t != null) { for (var i = 0; i < t; i++) { o[i] = n[Random().nextInt(e ?? n.length)]; } } else { o[8] = o[13] = o[18] = o[23] = "-"; o[14] = "4"; for (var i = 0; i < 36; i++) { if (o[i].isEmpty) { var r = Random().nextInt(16); o[i] = n[19 == i ? 3 & r | 8 : r]; } } } return o.join(""); } // String getRealUrl(String e) { // //https://github.com/wbt5/real-url/blob/master/huya.py // //使用ChatGPT转换的Dart代码,ChatGPT真好用 // List iAndB = e.split('?'); // String i = iAndB[0]; // String b = iAndB[1]; // List r = i.split('/'); // String s = r[r.length - 1].replaceAll(RegExp(r'.(flv|m3u8)'), ''); // List bs = b.split('&'); // List c = []; // c.addAll(bs.take(3)); // c.add(bs.skip(3).join("&")); // Map n = {}; // for (var str in c) { // List keyValue = str.split('='); // n[keyValue[0]] = keyValue[1]; // } // String fm = Uri.decodeFull(n['fm'] ?? "").split("&")[0]; // String u = utf8.decode(base64Decode(fm)); // String p = u.split('_')[0]; // String f = (DateTime.now().millisecondsSinceEpoch * 1000).toString(); // String l = n['wsTime'] ?? ""; // String t = '0'; // String h = [p, t, s, f, l].join("_"); // String m = md5.convert(utf8.encode(h)).toString(); // String y = c[c.length - 1]; // String url = "$i?wsSecret=$m&wsTime=$l&u=$t&seqid=$f&$y"; // url = url.replaceAll("&ctype=tars_mobile", ""); // url = url.replaceAll(RegExp(r"ratio=\d+&"), ""); // url = url.replaceAll(RegExp(r"imgplus_\d+"), "imgplus"); // return url; // } String processAnticode(String anticode, String uid, String streamname) { // 来源:https://github.com/iceking2nd/real-url/blob/master/huya.py // https://github.com/SeaHOH/ykdl/blob/master/ykdl/extractors/huya/live.py // 通过ChatGPT转换的Dart代码 var query = Uri.splitQueryString(anticode); query["t"] = "103"; query["ctype"] = "tars_mobile"; final wsTime = (DateTime.now().millisecondsSinceEpoch ~/ 1000 + 21600) .toRadixString(16); final seqId = (DateTime.now().millisecondsSinceEpoch + int.parse(uid)).toString(); final fm = utf8.decode(base64.decode(Uri.decodeComponent(query['fm']!))); final wsSecretPrefix = fm.split('_').first; final wsSecretHash = md5 .convert(utf8.encode('$seqId|${query["ctype"]}|${query["t"]}')) .toString(); final wsSecret = md5 .convert(utf8.encode( '${wsSecretPrefix}_${uid}_${streamname}_${wsSecretHash}_$wsTime')) .toString(); return Uri(queryParameters: { "wsSecret": wsSecret, "wsTime": wsTime, "seqid": seqId, "ctype": query["ctype"]!, "ver": "1", "fs": query["fs"]!, // "sphdcdn": query["sphdcdn"] ?? "", // "sphdDC": query["sphdDC"] ?? "", // "sphd": query["sphd"] ?? "", // "exsphd": query["exsphd"] ?? "", "dMod": "mseh-0", "sdkPcdn": "1_1", "uid": uid, "uuid": getUUid(), "t": query["t"]!, "sv": "202411221719", "sdk_sid": "1732862566708", "a_block": "0" }).query; } @override Future> getSuperChatMessage( {required String roomId}) { //尚不支持 return Future.value([]); } } class HuyaUrlDataModel { final String url; final String uid; List lines; List bitRates; HuyaUrlDataModel({ required this.bitRates, required this.lines, required this.url, required this.uid, }); @override String toString() { return json.encode({ "url": url, "uid": uid, "lines": lines.map((e) => e.toString()).toList(), "bitRates": bitRates.map((e) => e.toString()).toList(), }); } } enum HuyaLineType { flv, hls, } class HuyaLineModel { final String line; final String cdnType; final String flvAntiCode; final String hlsAntiCode; final String streamName; final HuyaLineType lineType; int bitRate; final int presenterUid; // topSid = subSid = presenterUid HuyaLineModel({ required this.line, required this.lineType, required this.flvAntiCode, required this.hlsAntiCode, required this.streamName, required this.cdnType, this.bitRate = 0, required this.presenterUid, }); @override String toString() { return json.encode({ "line": line, "cdnType": cdnType, "flvAntiCode": flvAntiCode, "hlsAntiCode": hlsAntiCode, "streamName": streamName, "lineType": lineType.toString(), "presenterUid": presenterUid, }); } } class HuyaBitRateModel { final String name; final int bitRate; HuyaBitRateModel({ required this.bitRate, required this.name, }); @override String toString() { return json.encode({ "name": name, "bitRate": bitRate, }); } } ================================================ FILE: simple_live_core/lib/src/interface/live_danmaku.dart ================================================ import 'dart:async'; import 'package:simple_live_core/src/model/live_message.dart'; class LiveDanmaku { Function(LiveMessage msg)? onMessage; Function(String msg)? onClose; Function()? onReady; /// 心跳时间 int heartbeatTime = 0; /// 发生心跳 void heartbeat() {} /// 开始接收信息 Future start(dynamic args) { return Future.value(); } /// 停止接收信息 Future stop() { return Future.value(); } } ================================================ FILE: simple_live_core/lib/src/interface/live_site.dart ================================================ import 'package:simple_live_core/src/model/live_anchor_item.dart'; import '../interface/live_danmaku.dart'; import '../model/live_category_result.dart'; import '../model/live_message.dart'; import '../model/live_play_url.dart'; import '../model/live_room_detail.dart'; import '../model/live_search_result.dart'; import '../model/live_category.dart'; import '../model/live_play_quality.dart'; import '../model/live_room_item.dart'; class LiveSite { /// 站点唯一ID String id = ""; /// 站点名称 String name = ""; /// 站点名称 LiveDanmaku getDanmaku() => LiveDanmaku(); /// 读取网站的分类 Future> getCategores() { return Future.value([]); } /// 搜索直播间 Future searchRooms(String keyword, {int page = 1}) { return Future.value( LiveSearchRoomResult(hasMore: false, items: [])); } /// 搜索直播间 Future searchAnchors(String keyword, {int page = 1}) { return Future.value( LiveSearchAnchorResult(hasMore: false, items: [])); } /// 读取类目下房间 Future getCategoryRooms(LiveSubCategory category, {int page = 1}) { return Future.value( LiveCategoryResult(hasMore: false, items: [])); } /// 读取推荐的房间 Future getRecommendRooms({int page = 1}) { return Future.value( LiveCategoryResult(hasMore: false, items: [])); } /// 读取房间详情 Future getRoomDetail({required String roomId}) { return Future.value(LiveRoomDetail( cover: '', online: 0, roomId: '', status: false, title: '', url: '', userAvatar: '', userName: '', )); } /// 读取房间清晰度 Future> getPlayQualites( {required LiveRoomDetail detail}) { return Future.value([]); } /// 读取播放链接 Future getPlayUrls( {required LiveRoomDetail detail, required LivePlayQuality quality}) { return Future.value(LivePlayUrl(urls: [])); } /// 查询直播状态 Future getLiveStatus({required String roomId}) { return Future.value(false); } /// 读取指定房间的SC Future> getSuperChatMessage( {required String roomId}) { return Future.value([]); } } ================================================ FILE: simple_live_core/lib/src/model/live_anchor_item.dart ================================================ import 'dart:convert'; class LiveAnchorItem { /// 房间ID final String roomId; /// 封面 final String avatar; /// 用户名 final String userName; /// 直播中 final bool liveStatus; LiveAnchorItem({ required this.roomId, required this.avatar, required this.userName, required this.liveStatus, }); @override String toString() { return json.encode({ "roomId": roomId, "avatar": avatar, "userName": userName, "liveStatus": liveStatus, }); } } ================================================ FILE: simple_live_core/lib/src/model/live_category.dart ================================================ import 'dart:convert'; class LiveCategory { final String name; final String id; final List children; LiveCategory({ required this.id, required this.name, required this.children, }); @override String toString() { return json.encode({ "name": name, "id": id, "children": children, }); } } class LiveSubCategory { final String name; final String? pic; final String id; final String parentId; LiveSubCategory({ required this.id, required this.name, required this.parentId, this.pic, }); @override String toString() { return json.encode({ "name": name, "id": id, "parentId": parentId, "pic": pic, }); } } ================================================ FILE: simple_live_core/lib/src/model/live_category_result.dart ================================================ import 'package:simple_live_core/src/model/live_room_item.dart'; class LiveCategoryResult { final bool hasMore; final List items; LiveCategoryResult({ required this.hasMore, required this.items, }); } ================================================ FILE: simple_live_core/lib/src/model/live_message.dart ================================================ import 'dart:convert'; enum LiveMessageType { /// 聊天 chat, /// 礼物,暂时不支持 gift, /// 在线人数 online, /// 醒目留言 superChat, } class LiveMessage { /// 消息类型 final LiveMessageType type; /// 用户名 final String userName; /// 信息 final String message; /// 数据 /// 单Type=Online时,Data为人气值(long) final dynamic data; /// 弹幕颜色 final LiveMessageColor color; LiveMessage({ required this.type, required this.userName, required this.message, this.data, required this.color, }); @override String toString() { return json.encode({ "type": type.index, "userName": userName, "message": message, "data": data.toString(), "color": color.toString(), }); } } class LiveMessageColor { final int r, g, b; LiveMessageColor(this.r, this.g, this.b); static LiveMessageColor get white => LiveMessageColor(255, 255, 255); static LiveMessageColor numberToColor(int intColor) { var obj = intColor.toRadixString(16); LiveMessageColor color = LiveMessageColor.white; if (obj.length == 4) { obj = "00$obj"; } if (obj.length == 6) { var R = int.parse(obj.substring(0, 2), radix: 16); var G = int.parse(obj.substring(2, 4), radix: 16); var B = int.parse(obj.substring(4, 6), radix: 16); color = LiveMessageColor(R, G, B); } if (obj.length == 8) { var R = int.parse(obj.substring(2, 4), radix: 16); var G = int.parse(obj.substring(4, 6), radix: 16); var B = int.parse(obj.substring(6, 8), radix: 16); //var A = int.parse(obj.substring(0, 2), radix: 16); color = LiveMessageColor(R, G, B); } return color; } @override String toString() { return "#${r.toRadixString(16).padLeft(2, '0')}${g.toRadixString(16).padLeft(2, '0')}${b.toRadixString(16).padLeft(2, '0')}"; } } class LiveSuperChatMessage { final String userName; final String face; final String message; final int price; final DateTime startTime; final DateTime endTime; final String backgroundColor; final String backgroundBottomColor; LiveSuperChatMessage({ required this.backgroundBottomColor, required this.backgroundColor, required this.endTime, required this.face, required this.message, required this.price, required this.startTime, required this.userName, }); @override String toString() { return json.encode({ "userName": userName, "face": face, "message": message, "price": price, "startTime": startTime, "endTime": endTime, "backgroundColor": backgroundColor, "backgroundBottomColor": backgroundBottomColor, }); } } ================================================ FILE: simple_live_core/lib/src/model/live_play_quality.dart ================================================ import 'dart:convert'; class LivePlayQuality { /// 清晰度 final String quality; /// 清晰度信息 final dynamic data; final int sort; LivePlayQuality({ required this.quality, required this.data, this.sort = 0, }); @override String toString() { return json.encode({ "quality": quality, "data": data.toString(), }); } } ================================================ FILE: simple_live_core/lib/src/model/live_play_url.dart ================================================ import 'dart:convert'; class LivePlayUrl { /// 播放地址 final List urls; /// 请求头 final Map? headers; LivePlayUrl({ required this.urls, this.headers, }); @override String toString() { return json.encode({ "urls": urls, "headers": headers.toString(), }); } } ================================================ FILE: simple_live_core/lib/src/model/live_room_detail.dart ================================================ import 'dart:convert'; class LiveRoomDetail { /// 房间ID final String roomId; /// 房间标题 final String title; /// 封面 final String cover; /// 用户名 final String userName; /// 头像 final String userAvatar; /// 在线 final int online; /// 介绍 final String? introduction; /// 公告 final String? notice; /// 状态 final bool status; /// 附加信息 final dynamic data; /// 弹幕附加信息 final dynamic danmakuData; /// 是否录播 final bool isRecord; /// 链接 final String url; /// 显示时间 final String? showTime; LiveRoomDetail({ required this.roomId, required this.title, required this.cover, required this.userName, required this.userAvatar, required this.online, this.introduction, this.notice, required this.status, this.data, this.danmakuData, required this.url, this.isRecord = false, this.showTime, }); @override String toString() { return json.encode({ "roomId": roomId, "title": title, "cover": cover, "userName": userName, "userAvatar": userAvatar, "online": online, "introduction": introduction, "notice": notice, "status": status, "data": data.toString(), "danmakuData": danmakuData.toString(), "url": url, "isRecord": isRecord, "showTime": showTime, }); } } ================================================ FILE: simple_live_core/lib/src/model/live_room_item.dart ================================================ import 'dart:convert'; class LiveRoomItem { /// 房间ID final String roomId; /// 标题 final String title; /// 封面 final String cover; /// 用户名 final String userName; /// 人气/在线人数 final int online; LiveRoomItem({ required this.roomId, required this.title, required this.cover, required this.userName, this.online = 0, }); @override String toString() { return json.encode({ "roomId": roomId, "title": title, "cover": cover, "userName": userName, "online": online, }); } } ================================================ FILE: simple_live_core/lib/src/model/live_search_result.dart ================================================ import 'package:simple_live_core/src/model/live_anchor_item.dart'; import 'package:simple_live_core/src/model/live_room_item.dart'; class LiveSearchRoomResult { final bool hasMore; final List items; LiveSearchRoomResult({ required this.hasMore, required this.items, }); } class LiveSearchAnchorResult { final bool hasMore; final List items; LiveSearchAnchorResult({ required this.hasMore, required this.items, }); } ================================================ FILE: simple_live_core/lib/src/model/tars/get_cdn_token_ex_req.dart ================================================  import 'package:tars_dart/tars/codec/tars_displayer.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/codec/tars_struct.dart'; import 'huya_user_id.dart'; class GetCdnTokenExReq extends TarsStruct { String sFlvUrl = ""; //tag 0 String sStreamName = ""; //tag 1 int iLoopTime = 0; //tag 2 HuyaUserId tId = HuyaUserId(); //tag 3 int iAppId = 66; //tag 4 @override void readFrom(TarsInputStream _is) { sFlvUrl = _is.read(sFlvUrl, 0, false); sStreamName = _is.read(sStreamName, 1, false); iLoopTime = _is.read(iLoopTime, 2, false); tId = _is.read(tId, 3, false); iAppId = _is.read(iAppId, 4, false); } @override void writeTo(TarsOutputStream _os) { _os.write(sFlvUrl, 0); _os.write(sStreamName, 1); _os.write(iLoopTime, 2); _os.write(tId, 3); _os.write(iAppId, 4); } @override TarsStruct deepCopy() { return GetCdnTokenExReq() ..sFlvUrl = sFlvUrl ..sStreamName = sStreamName ..iLoopTime = iLoopTime ..tId = tId ..iAppId = iAppId; } @override displayAsString(StringBuffer sb, int level) { TarsDisplayer _ds = TarsDisplayer(sb, level: level); _ds.DisplayString(sFlvUrl, "sFlvUrl"); _ds.DisplayString(sStreamName, "sStreamName"); _ds.DisplayInt(iLoopTime, "iLoopTime"); _ds.DisplayTarsStruct(tId, "tId"); _ds.DisplayInt(iAppId, "iAppId"); } } ================================================ FILE: simple_live_core/lib/src/model/tars/get_cdn_token_ex_resp.dart ================================================ import 'package:tars_dart/tars/codec/tars_displayer.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/codec/tars_struct.dart'; class GetCdnTokenExResp extends TarsStruct { String sFlvToken = ""; //tag 0 int iExpireTime = 0; //tag 1 @override void readFrom(TarsInputStream _is) { sFlvToken = _is.read(sFlvToken, 0, false); iExpireTime = _is.read(iExpireTime, 1, false); } @override void writeTo(TarsOutputStream _os) { _os.write(sFlvToken, 0); _os.write(iExpireTime, 1); } @override TarsStruct deepCopy() { return GetCdnTokenExResp() ..sFlvToken = sFlvToken ..iExpireTime = iExpireTime; } @override displayAsString(StringBuffer sb, int level) { TarsDisplayer _ds = TarsDisplayer(sb, level: level); _ds.DisplayString(sFlvToken, "sFlvToken"); _ds.DisplayInt(iExpireTime, "iExpireTime"); } } ================================================ FILE: simple_live_core/lib/src/model/tars/get_cdn_token_req.dart ================================================ // ignore_for_file: no_leading_underscores_for_local_identifiers import 'package:tars_dart/tars/codec/tars_displayer.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/codec/tars_struct.dart'; class GetCdnTokenReq extends TarsStruct { String url = ""; String cdnType = ""; String streamName = ""; int presenterUid = 0; @override void readFrom(TarsInputStream _is) { url = _is.read(url, 0, false); cdnType = _is.read(cdnType, 1, false); streamName = _is.read(streamName, 2, false); presenterUid = _is.read(presenterUid, 3, false); } @override void writeTo(TarsOutputStream _os) { _os.write(url, 0); _os.write(cdnType, 1); _os.write(streamName, 2); _os.write(presenterUid, 3); } @override Object deepCopy() { return GetCdnTokenReq() ..url = url ..cdnType = cdnType ..streamName = streamName ..presenterUid = presenterUid; } @override void displayAsString(StringBuffer sb, int level) { TarsDisplayer _ds = TarsDisplayer(sb, level: level); _ds.DisplayString(url, "url"); _ds.DisplayString(cdnType, "cdnType"); _ds.DisplayString(streamName, "streamName"); _ds.DisplayInt(presenterUid, "presenterUid"); } } ================================================ FILE: simple_live_core/lib/src/model/tars/get_cdn_token_resp.dart ================================================ // ignore_for_file: no_leading_underscores_for_local_identifiers import 'package:tars_dart/tars/codec/tars_displayer.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/codec/tars_struct.dart'; class GetCdnTokenResp extends TarsStruct { String url = ""; String cdnType = ""; String streamName = ""; int presenterUid = 0; String antiCode = ""; String sTime = ""; String flvAntiCode = ""; String hlsAntiCode = ""; @override void readFrom(TarsInputStream _is) { url = _is.read(url, 0, false); cdnType = _is.read(cdnType, 1, false); streamName = _is.read(streamName, 2, false); presenterUid = _is.read(presenterUid, 3, false); antiCode = _is.read(antiCode, 4, false); sTime = _is.read(sTime, 5, false); flvAntiCode = _is.read(flvAntiCode, 6, false); hlsAntiCode = _is.read(hlsAntiCode, 7, false); } @override void writeTo(TarsOutputStream _os) { _os.write(url, 0); _os.write(cdnType, 1); _os.write(streamName, 2); _os.write(presenterUid, 3); _os.write(antiCode, 4); _os.write(sTime, 5); _os.write(flvAntiCode, 6); _os.write(hlsAntiCode, 7); } @override Object deepCopy() { return GetCdnTokenResp() ..url = url ..cdnType = cdnType ..streamName = streamName ..presenterUid = presenterUid ..antiCode = antiCode ..sTime = sTime ..flvAntiCode = flvAntiCode ..hlsAntiCode = hlsAntiCode; } @override void displayAsString(StringBuffer sb, int level) { TarsDisplayer _ds = TarsDisplayer(sb, level: level); _ds.DisplayString(url, "url"); _ds.DisplayString(cdnType, "cdnType"); _ds.DisplayString(streamName, "streamName"); _ds.DisplayInt(presenterUid, "presenterUid"); _ds.DisplayString(antiCode, "antiCode"); _ds.DisplayString(sTime, "sTime"); _ds.DisplayString(flvAntiCode, "flvAntiCode"); _ds.DisplayString(hlsAntiCode, "hlsAntiCode"); } } ================================================ FILE: simple_live_core/lib/src/model/tars/huya_danmaku.dart ================================================ // ignore_for_file: no_leading_underscores_for_local_identifiers import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/codec/tars_struct.dart'; class HYPushMessage extends TarsStruct { int pushType = 0; int uri = 0; List msg = []; int protocolType = 0; @override void readFrom(TarsInputStream _is) { pushType = _is.read(pushType, 0, false); uri = _is.read(uri, 1, false); msg = _is.readBytes(2, false); protocolType = _is.read(protocolType, 3, false); } @override void writeTo(TarsOutputStream _os) {} @override Object deepCopy() { return HYPushMessage() ..pushType = pushType ..uri = uri ..msg = List.from(msg) ..protocolType = protocolType; } @override void displayAsString(StringBuffer sb, int level) {} } class HYSender extends TarsStruct { int uid = 0; int lMid = 0; String nickName = ""; int gender = 0; @override void readFrom(TarsInputStream _is) { uid = _is.read(uid, 0, false); lMid = _is.read(lMid, 0, false); nickName = _is.read(nickName, 2, false); gender = _is.read(gender, 3, false); } @override void writeTo(TarsOutputStream _os) {} @override Object deepCopy() { return HYSender() ..uid = uid ..lMid = lMid ..nickName = nickName ..gender = gender; } @override void displayAsString(StringBuffer sb, int level) {} } class HYMessage extends TarsStruct { HYSender userInfo = HYSender(); String content = ""; HYBulletFormat bulletFormat = HYBulletFormat(); @override void readFrom(TarsInputStream _is) { userInfo = _is.readTarsStruct(userInfo, 0, false) as HYSender; content = _is.read(content, 3, false); bulletFormat = _is.readTarsStruct(bulletFormat, 6, false) as HYBulletFormat; } @override void writeTo(TarsOutputStream _os) {} @override Object deepCopy() { return HYMessage() ..userInfo = userInfo.deepCopy() as HYSender ..content = content ..bulletFormat = bulletFormat.deepCopy() as HYBulletFormat; } @override void displayAsString(StringBuffer sb, int level) {} } class HYBulletFormat extends TarsStruct { int fontColor = 0; int fontSize = 4; int textSpeed = 0; int transitionType = 1; @override void readFrom(TarsInputStream _is) { fontColor = _is.read(fontColor, 0, false); fontSize = _is.read(fontSize, 1, false); textSpeed = _is.read(textSpeed, 2, false); transitionType = _is.read(transitionType, 3, false); } @override void writeTo(TarsOutputStream _os) {} @override Object deepCopy() { return HYBulletFormat() ..fontColor = fontColor ..fontSize = fontSize ..textSpeed = textSpeed ..transitionType = transitionType; } @override void displayAsString(StringBuffer sb, int level) {} } ================================================ FILE: simple_live_core/lib/src/model/tars/huya_user_id.dart ================================================ import 'package:tars_dart/tars/codec/tars_displayer.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/codec/tars_struct.dart'; class HuyaUserId extends TarsStruct { int lUid = 0; String sGuid = ""; String sToken = ""; String sHuYaUA = ""; String sCookie = ""; int iTokenType = 0; String sDeviceInfo = ""; String sQIMEI = ""; @override void readFrom(TarsInputStream _is) { lUid = _is.read(lUid, 0, false); sGuid = _is.read(sGuid, 1, false); sToken = _is.read(sToken, 2, false); sHuYaUA = _is.read(sHuYaUA, 3, false); sCookie = _is.read(sCookie, 4, false); iTokenType = _is.read(iTokenType, 5, false); sDeviceInfo = _is.read(sDeviceInfo, 6, false); sQIMEI = _is.read(sQIMEI, 7, false); } @override void writeTo(TarsOutputStream _os) { _os.write(lUid, 0); _os.write(sGuid, 1); _os.write(sToken, 2); _os.write(sHuYaUA, 3); _os.write(sCookie, 4); _os.write(iTokenType, 5); _os.write(sDeviceInfo, 6); _os.write(sQIMEI, 7); } @override Object deepCopy() { return HuyaUserId() ..lUid = lUid ..sGuid = sGuid ..sToken = sToken ..sHuYaUA = sHuYaUA ..sCookie = sCookie ..iTokenType = iTokenType ..sDeviceInfo = sDeviceInfo ..sQIMEI = sQIMEI; } @override void displayAsString(StringBuffer sb, int level) { TarsDisplayer _ds = TarsDisplayer(sb, level: level); _ds.DisplayInt(lUid, "lUid"); _ds.DisplayString(sGuid, "sGuid"); _ds.DisplayString(sToken, "sToken"); _ds.DisplayString(sHuYaUA, "sHuYaUA"); _ds.DisplayString(sCookie, "sCookie"); _ds.DisplayInt(iTokenType, "iTokenType"); _ds.DisplayString(sDeviceInfo, "sDeviceInfo"); _ds.DisplayString(sQIMEI, "sQIMEI"); } } ================================================ FILE: simple_live_core/lib/src/model/tars/tar2dart.dart ================================================ import 'dart:io'; // 需要所有字段有 //tag n 注释方便定位-多行编辑生成 // 可以自动生成这个tag,懒得弄了 final fieldRegex = RegExp( r'^\s*(\w+(?:<[^>]+>)?)\s+(\w+)\s*=\s*[^;]+;\s*//\s*tag\s*(\d+)', ); final classRegex = RegExp(r'class\s+(\w+)\s+extends\s+TarsStruct'); void main(List args) { if (args.isEmpty) { print('Usage: dart run tars_codegen.dart '); exit(1); } final file = File(args[0]); final lines = file.readAsLinesSync(); final fields = []; for (final line in lines) { final m = classRegex.firstMatch(line); if (m != null) { className = m.group(1); break; } } if (className == null) { throw Exception('No class extends TarsStruct found'); } for (final line in lines) { final match = fieldRegex.firstMatch(line); if (match != null) { fields.add(Field( type: match.group(1)!, name: match.group(2)!, tag: int.parse(match.group(3)!), )); } } fields.sort((a, b) => a.tag.compareTo(b.tag)); print(generate(fields)); } String generate(List fields) { final sb = StringBuffer(); // readFrom sb.writeln('@override'); sb.writeln('void readFrom(TarsInputStream _is) {'); for (final f in fields) { sb.writeln( ' ${padRight(f.name, 20)} = _is.read(${f.name}, ${f.tag}, false);', ); } sb.writeln('}\n'); // writeTo sb.writeln('@override'); sb.writeln('void writeTo(TarsOutputStream _os) {'); for (final f in fields) { sb.writeln(' _os.write(${f.name}, ${f.tag});'); } sb.writeln('}\n'); // deepCopy sb.writeln('@override'); sb.writeln('TarsStruct deepCopy() {'); sb.writeln(' return $className()'); for (final f in fields) { sb.writeln(' ..${f.name} = ${f.name}'); } sb.writeln(' ;'); sb.writeln('}\n'); // display sb.writeln('@override'); sb.writeln('displayAsString(StringBuffer sb, int level) {'); sb.writeln(' TarsDisplayer _ds = TarsDisplayer(sb, level: level);'); for (final f in fields) { sb.writeln( ' _ds.${displayMethod(f.type)}(${f.name}, "${f.name}");', ); } sb.writeln('}'); return sb.toString(); } String displayMethod(String type) { if (type.startsWith('List')) return 'DisplayList'; if (type.startsWith('Map')) return 'DisplayMap'; if (type == 'String') return 'DisplayString'; if (type == 'int') return 'DisplayInt'; return 'DisplayTarsStruct'; } String padRight(String s, int width) => s + ' ' * (width - s.length); late String? className; class Field { final String type; final String name; final int tag; Field({ required this.type, required this.name, required this.tag, }); } ================================================ FILE: simple_live_core/lib/src/scripts/douyin_sign.dart ================================================ import 'dart:math'; import 'package:dart_quickjs/dart_quickjs.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:crypto/crypto.dart'; class DouyinSign { static const kABogus = r''' function getABogus(params, userAgent) { // All the content in this article is only for learning and communication use, not for any other purpose, strictly prohibited for commercial use and illegal use, otherwise all the consequences are irrelevant to the author! function rc4_encrypt(plaintext, key) { var s = []; for (var i = 0; i < 256; i++) { s[i] = i; } var j = 0; for (var i = 0; i < 256; i++) { j = (j + s[i] + key.charCodeAt(i % key.length)) % 256; var temp = s[i]; s[i] = s[j]; s[j] = temp; } var i = 0; var j = 0; var cipher = []; for (var k = 0; k < plaintext.length; k++) { i = (i + 1) % 256; j = (j + s[i]) % 256; var temp = s[i]; s[i] = s[j]; s[j] = temp; var t = (s[i] + s[j]) % 256; cipher.push(String.fromCharCode(s[t] ^ plaintext.charCodeAt(k))); } return cipher.join(''); } function le(e, r) { return (e << (r %= 32) | e >>> 32 - r) >>> 0 } function de(e) { return 0 <= e && e < 16 ? 2043430169 : 16 <= e && e < 64 ? 2055708042 : void console['error']("invalid j for constant Tj") } function pe(e, r, t, n) { return 0 <= e && e < 16 ? (r ^ t ^ n) >>> 0 : 16 <= e && e < 64 ? (r & t | r & n | t & n) >>> 0 : (console['error']('invalid j for bool function FF'), 0) } function he(e, r, t, n) { return 0 <= e && e < 16 ? (r ^ t ^ n) >>> 0 : 16 <= e && e < 64 ? (r & t | ~r & n) >>> 0 : (console['error']('invalid j for bool function GG'), 0) } function reset() { this.reg[0] = 1937774191, this.reg[1] = 1226093241, this.reg[2] = 388252375, this.reg[3] = 3666478592, this.reg[4] = 2842636476, this.reg[5] = 372324522, this.reg[6] = 3817729613, this.reg[7] = 2969243214, this["chunk"] = [], this["size"] = 0 } function write(e) { var a = "string" == typeof e ? function (e) { n = encodeURIComponent(e)['replace'](/%([0-9A-F]{2})/g, (function (e, r) { return String['fromCharCode']("0x" + r) } )) , a = new Array(n['length']); return Array['prototype']['forEach']['call'](n, (function (e, r) { a[r] = e.charCodeAt(0) } )), a }(e) : e; this.size += a.length; var f = 64 - this['chunk']['length']; if (a['length'] < f) this['chunk'] = this['chunk'].concat(a); else for (this['chunk'] = this['chunk'].concat(a.slice(0, f)); this['chunk'].length >= 64;) this['_compress'](this['chunk']), f < a['length'] ? this['chunk'] = a['slice'](f, Math['min'](f + 64, a['length'])) : this['chunk'] = [], f += 64 } function sum(e, t) { e && (this['reset'](), this['write'](e)), this['_fill'](); for (var f = 0; f < this.chunk['length']; f += 64) this._compress(this['chunk']['slice'](f, f + 64)); var i = null; if (t == 'hex') { i = ""; for (f = 0; f < 8; f++) i += se(this['reg'][f]['toString'](16), 8, "0") } else for (i = new Array(32), f = 0; f < 8; f++) { var c = this.reg[f]; i[4 * f + 3] = (255 & c) >>> 0, c >>>= 8, i[4 * f + 2] = (255 & c) >>> 0, c >>>= 8, i[4 * f + 1] = (255 & c) >>> 0, c >>>= 8, i[4 * f] = (255 & c) >>> 0 } return this['reset'](), i } function _compress(t) { if (t < 64) console.error("compress error: not enough data"); else { for (var f = function (e) { for (var r = new Array(132), t = 0; t < 16; t++) r[t] = e[4 * t] << 24, r[t] |= e[4 * t + 1] << 16, r[t] |= e[4 * t + 2] << 8, r[t] |= e[4 * t + 3], r[t] >>>= 0; for (var n = 16; n < 68; n++) { var a = r[n - 16] ^ r[n - 9] ^ le(r[n - 3], 15); a = a ^ le(a, 15) ^ le(a, 23), r[n] = (a ^ le(r[n - 13], 7) ^ r[n - 6]) >>> 0 } for (n = 0; n < 64; n++) r[n + 68] = (r[n] ^ r[n + 4]) >>> 0; return r }(t), i = this['reg'].slice(0), c = 0; c < 64; c++) { var o = le(i[0], 12) + i[4] + le(de(c), c) , s = ((o = le(o = (4294967295 & o) >>> 0, 7)) ^ le(i[0], 12)) >>> 0 , u = pe(c, i[0], i[1], i[2]); u = (4294967295 & (u = u + i[3] + s + f[c + 68])) >>> 0; var b = he(c, i[4], i[5], i[6]); b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0, i[3] = i[2], i[2] = le(i[1], 9), i[1] = i[0], i[0] = u, i[7] = i[6], i[6] = le(i[5], 19), i[5] = i[4], i[4] = (b ^ le(b, 9) ^ le(b, 17)) >>> 0 } for (var l = 0; l < 8; l++) this['reg'][l] = (this['reg'][l] ^ i[l]) >>> 0 } } function _fill() { var a = 8 * this['size'] , f = this['chunk']['push'](128) % 64; for (64 - f < 8 && (f -= 64); f < 56; f++) this.chunk['push'](0); for (var i = 0; i < 4; i++) { var c = Math['floor'](a / 4294967296); this['chunk'].push(c >>> 8 * (3 - i) & 255) } for (i = 0; i < 4; i++) this['chunk']['push'](a >>> 8 * (3 - i) & 255) } function SM3() { this.reg = []; this.chunk = []; this.size = 0; this.reset() } SM3.prototype.reset = reset; SM3.prototype.write = write; SM3.prototype.sum = sum; SM3.prototype._compress = _compress; SM3.prototype._fill = _fill; function result_encrypt(long_str, num = null) { let s_obj = { "s0": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", "s1": "Dkdpgh4ZKsQB80/Mfvw36XI1R25+WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=", "s2": "Dkdpgh4ZKsQB80/Mfvw36XI1R25-WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe=", "s3": "ckdp1h4ZKsUB80/Mfvw36XIgR25+WQAlEi7NLboqYTOPuzmFjJnryx9HVGDaStCe", "s4": "Dkdpgh2ZmsQB80/MfvV36XI1R45-WUAlEixNLwoqYTOPuzKFjJnry79HbGcaStCe" } let constant = { "0": 16515072, "1": 258048, "2": 4032, "str": s_obj[num], } let result = ""; let lound = 0; let long_int = get_long_int(lound, long_str); for (let i = 0; i < long_str.length / 3 * 4; i++) { if (Math.floor(i / 4) !== lound) { lound += 1; long_int = get_long_int(lound, long_str); } let key = i % 4; switch (key) { case 0: temp_int = (long_int & constant["0"]) >> 18; result += constant["str"].charAt(temp_int); break; case 1: temp_int = (long_int & constant["1"]) >> 12; result += constant["str"].charAt(temp_int); break; case 2: temp_int = (long_int & constant["2"]) >> 6; result += constant["str"].charAt(temp_int); break; case 3: temp_int = long_int & 63; result += constant["str"].charAt(temp_int); break; default: break; } } return result; } function get_long_int(round, long_str) { round = round * 3; return (long_str.charCodeAt(round) << 16) | (long_str.charCodeAt(round + 1) << 8) | (long_str.charCodeAt(round + 2)); } function gener_random(random, option) { return [ (random & 255 & 170) | option[0] & 85, // 163 (random & 255 & 85) | option[0] & 170, //87 (random >> 8 & 255 & 170) | option[1] & 85, //37 (random >> 8 & 255 & 85) | option[1] & 170, //41 ] } ////////////////////////////////////////////// function generate_rc4_bb_str(url_search_params, user_agent, window_env_str, suffix = "cus", Arguments = [0, 1, 14]) { let sm3 = new SM3() let start_time = Date.now() /** * 进行3次加密处理 * 1: url_search_params两次sm3之的结果 * 2: 对后缀两次sm3之的结果 * 3: 对ua处理之后的结果 */ // url_search_params两次sm3之的结果 let url_search_params_list = sm3.sum(sm3.sum(url_search_params + suffix)) // 对后缀两次sm3之的结果 let cus = sm3.sum(sm3.sum(suffix)) // 对ua处理之后的结果 let ua = sm3.sum(result_encrypt(rc4_encrypt(user_agent, String.fromCharCode.apply(null, [0.00390625, 1, 14])), "s3")) // let end_time = Date.now() // b let b = { 8: 3, // 固定 10: end_time, //3次加密结束时间 15: { "aid": 6383, "pageId": 6241, "boe": false, "ddrt": 7, "paths": { "include": [ {}, {}, {}, {}, {}, {}, {} ], "exclude": [] }, "track": { "mode": 0, "delay": 300, "paths": [] }, "dump": true, "rpU": "" }, 16: start_time, //3次加密开始时间 18: 44, //固定 19: [1, 0, 1, 5], } //3次加密开始时间 b[20] = (b[16] >> 24) & 255 b[21] = (b[16] >> 16) & 255 b[22] = (b[16] >> 8) & 255 b[23] = b[16] & 255 b[24] = (b[16] / 256 / 256 / 256 / 256) >> 0 b[25] = (b[16] / 256 / 256 / 256 / 256 / 256) >> 0 // 参数Arguments [0, 1, 14, ...] // let Arguments = [0, 1, 14] b[26] = (Arguments[0] >> 24) & 255 b[27] = (Arguments[0] >> 16) & 255 b[28] = (Arguments[0] >> 8) & 255 b[29] = Arguments[0] & 255 b[30] = (Arguments[1] / 256) & 255 b[31] = (Arguments[1] % 256) & 255 b[32] = (Arguments[1] >> 24) & 255 b[33] = (Arguments[1] >> 16) & 255 b[34] = (Arguments[2] >> 24) & 255 b[35] = (Arguments[2] >> 16) & 255 b[36] = (Arguments[2] >> 8) & 255 b[37] = Arguments[2] & 255 // (url_search_params + "cus") 两次sm3之的结果 /**let url_search_params_list = [ 91, 186, 35, 86, 143, 253, 6, 76, 34, 21, 167, 148, 7, 42, 192, 219, 188, 20, 182, 85, 213, 74, 213, 147, 37, 155, 93, 139, 85, 118, 228, 213 ]*/ b[38] = url_search_params_list[21] b[39] = url_search_params_list[22] // ("cus") 对后缀两次sm3之的结果 /** * let cus = [ 136, 101, 114, 147, 58, 77, 207, 201, 215, 162, 154, 93, 248, 13, 142, 160, 105, 73, 215, 241, 83, 58, 51, 43, 255, 38, 168, 141, 216, 194, 35, 236 ]*/ b[40] = cus[21] b[41] = cus[22] // 对ua处理之后的结果 /** * let ua = [ 129, 190, 70, 186, 86, 196, 199, 53, 99, 38, 29, 209, 243, 17, 157, 69, 147, 104, 53, 23, 114, 126, 66, 228, 135, 30, 168, 185, 109, 156, 251, 88 ]*/ b[42] = ua[23] b[43] = ua[24] //3次加密结束时间 b[44] = (b[10] >> 24) & 255 b[45] = (b[10] >> 16) & 255 b[46] = (b[10] >> 8) & 255 b[47] = b[10] & 255 b[48] = b[8] b[49] = (b[10] / 256 / 256 / 256 / 256) >> 0 b[50] = (b[10] / 256 / 256 / 256 / 256 / 256) >> 0 // object配置项 b[51] = b[15]['pageId'] b[52] = (b[15]['pageId'] >> 24) & 255 b[53] = (b[15]['pageId'] >> 16) & 255 b[54] = (b[15]['pageId'] >> 8) & 255 b[55] = b[15]['pageId'] & 255 b[56] = b[15]['aid'] b[57] = b[15]['aid'] & 255 b[58] = (b[15]['aid'] >> 8) & 255 b[59] = (b[15]['aid'] >> 16) & 255 b[60] = (b[15]['aid'] >> 24) & 255 // 中间进行了环境检测 // 代码索引: 2496 索引值: 17 (索引64关键条件) // '1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32'.charCodeAt()得到65位数组 /** * let window_env_list = [49, 53, 51, 54, 124, 55, 52, 55, 124, 49, 53, 51, 54, 124, 56, 51, 52, 124, 48, 124, 51, * 48, 124, 48, 124, 48, 124, 49, 53, 51, 54, 124, 56, 51, 52, 124, 49, 53, 51, 54, 124, 56, * 54, 52, 124, 49, 53, 50, 53, 124, 55, 52, 55, 124, 50, 52, 124, 50, 52, 124, 87, 105, 110, * 51, 50] */ let window_env_list = []; for (let index = 0; index < window_env_str.length; index++) { window_env_list.push(window_env_str.charCodeAt(index)) } b[64] = window_env_list.length b[65] = b[64] & 255 b[66] = (b[64] >> 8) & 255 b[69] = [].length b[70] = b[69] & 255 b[71] = (b[69] >> 8) & 255 b[72] = b[18] ^ b[20] ^ b[26] ^ b[30] ^ b[38] ^ b[40] ^ b[42] ^ b[21] ^ b[27] ^ b[31] ^ b[35] ^ b[39] ^ b[41] ^ b[43] ^ b[22] ^ b[28] ^ b[32] ^ b[36] ^ b[23] ^ b[29] ^ b[33] ^ b[37] ^ b[44] ^ b[45] ^ b[46] ^ b[47] ^ b[48] ^ b[49] ^ b[50] ^ b[24] ^ b[25] ^ b[52] ^ b[53] ^ b[54] ^ b[55] ^ b[57] ^ b[58] ^ b[59] ^ b[60] ^ b[65] ^ b[66] ^ b[70] ^ b[71] let bb = [ b[18], b[20], b[52], b[26], b[30], b[34], b[58], b[38], b[40], b[53], b[42], b[21], b[27], b[54], b[55], b[31], b[35], b[57], b[39], b[41], b[43], b[22], b[28], b[32], b[60], b[36], b[23], b[29], b[33], b[37], b[44], b[45], b[59], b[46], b[47], b[48], b[49], b[50], b[24], b[25], b[65], b[66], b[70], b[71] ] bb = bb.concat(window_env_list).concat(b[72]) return rc4_encrypt(String.fromCharCode.apply(null, bb), String.fromCharCode.apply(null, [121])); } function generate_random_str() { let random_str_list = [] random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [3, 45])) random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [1, 0])) random_str_list = random_str_list.concat(gener_random(Math.random() * 10000, [1, 5])) return String.fromCharCode.apply(null, random_str_list) } function generate_a_bogus(url_search_params, user_agent) { /** * url_search_params:"device_platform=webapp&aid=6383&channel=channel_pc_web&update_version_code=170400&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=123.0.0.0&browser_online=true&engine_name=Blink&engine_version=123.0.0.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7362810250930783783&msToken=VkDUvz1y24CppXSl80iFPr6ez-3FiizcwD7fI1OqBt6IICq9RWG7nCvxKb8IVi55mFd-wnqoNkXGnxHrikQb4PuKob5Q-YhDp5Um215JzlBszkUyiEvR" * user_agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" */ let result_str = generate_random_str() + generate_rc4_bb_str( url_search_params, user_agent, "1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32" ); return result_encrypt(result_str, "s4") + "="; } //测试调用 // console.log(generate_a_bogus( // "device_platform=webapp&aid=6383&channel=channel_pc_web&update_version_code=170400&pc_client_type=1&version_code=170400&version_name=17.4.0&cookie_enabled=true&screen_width=1536&screen_height=864&browser_language=zh-CN&browser_platform=Win32&browser_name=Chrome&browser_version=123.0.0.0&browser_online=true&engine_name=Blink&engine_version=123.0.0.0&os_name=Windows&os_version=10&cpu_core_num=16&device_memory=8&platform=PC&downlink=10&effective_type=4g&round_trip_time=50&webid=7362810250930783783&msToken=VkDUvz1y24CppXSl80iFPr6ez-3FiizcwD7fI1OqBt6IICq9RWG7nCvxKb8IVi55mFd-wnqoNkXGnxHrikQb4PuKob5Q-YhDp5Um215JzlBszkUyiEvR", // "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" // )); return generate_a_bogus(params, userAgent); } '''; static const kWebMsSDK = r''' function getMSSDKSignature(msStub, userAgent) { document = {} window = {} navigator = { userAgent: userAgent } var crawler /** 1.0.0.53 */ if (!window.byted_acrawler) { function w_0x25f3(_0x545d0a, _0xb73ac6) { var _0x4173a9 = w_0x42f5() return ( (w_0x25f3 = function (_0x138003, _0x35a375) { _0x138003 = _0x138003 - (-0x1 * -0xd15 + -0x1044 + 0x48d) var _0x484578 = _0x4173a9[_0x138003] return _0x484578 }), w_0x25f3(_0x545d0a, _0xb73ac6) ) } ; (function (_0x2afeae, _0x11644f) { var _0x34f31d = w_0x25f3, _0x222a7c = _0x2afeae() while (!![]) { try { var _0x5a962 = (-parseInt(_0x34f31d(0x31b)) / (-0x1c * 0xac + 0x22 * 0x121 + 0x1 * -0x1391)) * (-parseInt(_0x34f31d(0x26a)) / (0xa27 * -0x1 + 0x683 * -0x5 + 0x4 * 0xaae)) + parseInt(_0x34f31d(0x296)) / (-0x18c1 + 0xa9a + 0x715 * 0x2) + (-parseInt(_0x34f31d(0x1f3)) / (0x446 * 0x4 + 0x649 + -0x175d)) * (parseInt(_0x34f31d(0x31c)) / (0x3 * -0xbbf + 0xf67 * 0x1 + -0x12b * -0x11)) + (parseInt(_0x34f31d(0x347)) / (-0x102f * 0x2 + 0x9e * 0x19 + 0x10f6)) * (-parseInt(_0x34f31d(0x28f)) / (-0x1 * 0x1817 + -0x1 * -0x184d + -0x2f)) + (-parseInt(_0x34f31d(0x241)) / (0x779 * -0x1 + -0x1e1d + 0x259e)) * (-parseInt(_0x34f31d(0x2b9)) / (-0x435 + -0x8c9 * 0x2 + 0x1 * 0x15d0)) + (-parseInt(_0x34f31d(0x295)) / (0x246e + 0x1 * -0x1c79 + 0x7eb * -0x1)) * (-parseInt(_0x34f31d(0x291)) / (-0x1b67 + -0x3c3 * -0x3 + 0x1029)) + (parseInt(_0x34f31d(0x307)) / (0x1c3d + -0xaa0 + 0x3 * -0x5db)) * (-parseInt(_0x34f31d(0x39d)) / (-0x18de + -0x3 * -0x6f7 + 0x406)) if (_0x5a962 === _0x11644f) break else _0x222a7c['push'](_0x222a7c['shift']()) } catch (_0x4c4ab0) { _0x222a7c['push'](_0x222a7c['shift']()) } } })(w_0x42f5, -0x131739 + 0x156382 + -0x7 * -0x144df) function w_0x42f5() { var _0x458f30 = [ '\x20can\x27t\x20have\x20a\x20.', '484e4f4a403f5243001f3009ad9ffc90000000dc0b1204fb00000477110001033f2e17000135491102004a120000110001110001031a2747000503414500201100010334274700050347450012110001033e2747000603041d45000303111d184301421101021400020211000211000103182c43010211000211000103122c43011802110002110001030c2c4301180211000211000103062c43011802110002110001430118421100011401010211010311000103022c430142110101031c2b11000103042d2f1400021100011401010211010311000243014202110103110101031a2b11000103062d2f4301021101021100014301184205000000003b0114000205000000473b01140003050000008b3b01140004050000009e3b0114000505000000be3b0114000603001400010300140007030014000811010144004a12000143000403e81b03002d14000911010212000232330033021101030211010303001100090700031843021101041200044a12000511010412000612000703021843014302050000fff11c140008110009110008050000fff11a3103002d4a1200080302430114000a11000a14000b11000a12000703202947001811000a4a12000511000a120007032019430114000b45004511000a12000703202747003907000314000c030014000d11000d032011000a120007192747001411000c0700091817000c354917000d214945ffdc11000c11000b1814000b07000a11000b18140007021101051100070302430214000702110103030011000707000318430214000e02110106430014000f11011807000b25470004014500010011000f07000c1607000314001011011612000d3300131101074a12000e11011612000d430107000f2647006503001400111101161200104700290211010803001101074a12000e0211010911011612000d1101161200104302430143021400114500200211010803001101074a12000e0211010a11011612000d43014301430214001107001111001118070012181400100211010b110116120013430114001211011612001447001511010c4a12001511001211011612001443024500031100121400121100100211010d110012430118140010110010070016180211010e1101161200134301180700121814001011001007001718070018181400100211010f11000f4301140013110102120002323300060211011043001400141101021200023233001811011112001934000f021101120211011307001a430143011400150211000411000743010211000511000706001b1b03002d4301180211000611001411000731430118021100040211010311000e1101021200023233000611011412001c4a12000843004302050000fff11c03102b0211010311000e110010070003184302050000fff11c2f4301180211000511001303082b11010212001d03042b2f110007314301180211000311000843011814001602110006030043014911001547000a1100161100151814001607001e1100161814001702110108030011001743024a120008031043011400181100184a12001f1100181200070302191100181200074302140019110017110019181400171100174200200c6b7f62604e656c7f4e626968076a6879596460680b6962604362795b6c6164690004657f686b097e786f7e797f64636a087d7f6279626e6261066168636a79650879625e797f64636a013d0e3c3d3d3d3d3d3d3d3c3c3d3d3d3d076b627f7f686c610a69647f686e795e646a63046f626974097e797f64636a646b740276700b6f6269745b6c613f7e797f0a6f62697452656c7e6530012b03787f61057c78687f740a6c7e626169527e646a63097d6c7965636c606830097979527a686f646930062b78786469300e526f74796869527e686e52696469077979527e6e64690a393f3439343b3a3f343b09787e687f4c6a686379096b685b687f7e6462630e523d3f4f39573b7a623d3d3d3d3c057e61646e68', '484e4f4a403f5243003c01321067d4bc00000824ebfd74540000087f0211010311000111000243024a12000505000000213b0105000001533b014302421100011200064701251100011200073300191100011200074a12000811030112000912000a430103011d2634000c0211030211000112000743014700f111000112000b4a12000c07000d43011400021100024700d902110303110001120007430114000311000311030412000e2547005511000211030515000f1100031103051500100211030607000f110002430249021103071100024301491100031101032947001f1103051200111200120300294700100211030811030903020403e81a4302494500161101031103051200102a47000911000211030515000f1101031103041200132533000c110305120011120012030a274700361103051200114a120014110002430149110305120011120012030125470017021103071100024301490211030607000f110002430249110001421100014008421100023400010d14000211020a33000711000111020b3714000307001514000407001614000507001514000611020c33000711000111020d374701c411000112000a14000411000212001747000f1100021200174a12001843004500030700161400050211020e1100044301330011110005070016253400071100050700192547017d11020512001014000711020512001a1400081100080700152347000f07000f11020512000f0c000245001207000f11020512000f07001a1100080c00041400090211020f021102101100044301110009430214000a0211021111000a430114000b0211021211000b11000212001b430214000c0211020f11000a11010111000c0c0002430214000d07001514000e11021312001c47000911000d14000e4500b10d021102140211000d43020e000714000f110005070019254700710211021511000111000243024a12001d07001e43010300134a12001f430014000602110216110006430147003b0211021711000f11000611000212001b4303490211021811000f0807002043031400100211020f11000d1101021100100c0002430214000e45000611000d14000e4500250211021811000f0807002043031400110211020f11000d1101021100110c0002430214000e1102131200214700130211021a430011000212000b110219120022160211010411000e1100021100074303421100034701e91100011200071400041100011200174700091100011200174500030700161400050211020e1100044301330011110005070016253400071100050700192547019811020512001014001211020512001a1400131100130700152347000f07000f11020512000f0c000245001207000f11020512000f07001a1100130c00041400140211020f021102101100044301110014430214001502110211110015430114001611000112000b1400171102131200214700161100174a1200231102191200220211021a4300430249110005070019254700480211021511000111000243024a12001d07001e43010300134a12001f43001400061100014a12002443004a12002543004a12000505000007293b01050000081e3b014302424500bd021102121100160243021400180211020f1100151101011100180c000243021400190d021102140211001943020e000714001a0211021811001a08070020430314001b0211020f11001911010211001b0c0002430214001c11020b11001c0d1100170e000b080e001b1100011200260e00261100011200270e00271100011200280e00281100011200290e002911000112002a0e002a11000112002b0e002b11000112002c0e002c440214001d0211010411001d110002110012430342021101031100011100024302424501df11000212000b324700070d11000215000b11000114000411000212001747000f1100021200174a12001843004500030700161400050211020e1100044301330011110005070016253400071100050700192547017d11020512001014001e11020512001a14001f11001f0700152347000f07000f11020512000f0c000245001207000f11020512000f07001a11001f0c00041400200211020f02110210110004430111002043021400210211021111002143011400220211021211002211000212001b43021400230211020f1100211101011100230c0002430214002407001514002511021312001c4700091100241400254500b10d021102140211002443020e0007140026110005070019254700710211021511000111000243024a12001d07001e43010300134a12001f430014000602110216110006430147003b0211021711002611000611000212001b430349021102181100260807002043031400270211020f1100241101021100270c00024302140025450006110024140025450025021102181100260807002043031400280211020f1100241101021100280c000243021400251102131200214700130211021a430011000212000b110219120022160211010411002511000211001e4303420211010311000111000243024208420700151400020211031211011611000143021400030211030f1101151102011100030c000243021400040211031611010643014700490d021103140211000443020e000714000502110317110005110106110001430349021103181100050807002043031400060211030f1100041102021100060c0002430214000245000611000414000211030b1100020d1101011200170e00171101170e000b1100010e001b1101011200260e00261101011200270e00271101011200280e00281101011200290e002911010112002a0e002a11010112002b0e002b11010112002c0e002c44021400070211020411000711010211011243034211000140084205000000003b0314000405000001593b021400050700001400010700011400020211010043003247000208421101011200024700020842001101011500021101011200031400031100031101011500041100051101011500030842002d0754214e636b797f0a537f656b626d78797e691653536d6f53656278697e6f697c786968536a69786f64056a69786f6406536a69786f64047864696202636703797e60076562686974436a0860636f6d7865636204647e696a0764696d68697e7f036b69780a7421617f217863676962037f696f07617f586367696208617f5f786d78797f0e617f42697b586367696240657f78066069626b78640465626578047c797f6400034b4958066169786463680b7863597c7c697e4f6d7f69045c435f580b53536d6f5378697f786568046e636875017a057f7c60657801370b786340637b697e4f6d7f69076a637e7e696d60037f68650d7f696f45626a6344696d68697e037f6978056f606362690478697478087e696a697e7e697e0e7e696a697e7e697e5c6360656f7504616368690b6f7e6968696278656d607f056f6d6f6469087e6968657e696f7809656278696b7e657875', 'own', 'Super\x20expression\x20must\x20either\x20be\x20null\x20or\x20a\x20function', 'getTimezoneOffset', 'array', 'toDataURL', 'enumerable', 'setPrototypeOf', 'field', 'WEBGL', 'wID', 'illegal\x20catch\x20attempt', 'TouchEvent', '3160hBpQVk', '484e4f4a403f5243000d0a13c08652000000000f3be74070000003930211021611010111000143024908421101003300031101013300031101023247000208420d0700000e000103040e00021101181200000e00030d0700040e000103030e00021101030e00050d0700060e000103030e00021101040e00050d0700070e000103030e00021101050e00050d0700080e000103030e00021101030e00050d0700090e000103000e00020d07000a0e000103000e00020d07000b0e000103000e00020d07000c0e000103000e00020d07000d0e000103000e00020d07000e0e000103030e00021101060e00050d07000f0e000103030e00021101070e00050d0700100e000103010e00020d0700110e000103010e00020d0700120e000103010e00020d0700130e000103000e00020d0700140e000103030e00021101080e000503010e00150d0700160e000103030e00021101090e00050d0700170e000103030e000211010a0e00050d0700180e000103030e00021101030e00050d0700190e000103030e000211010b0e00050d07001a0e000103030e000211010c0e00050d07001b0e000103030e000211010d0e00050d07001c0e000103030e00021101030e00050d07001d0e000103000e00020d07001e0e000103030e000211010e0e000507001f0e00200d0700210e000103030e000211010f0e00050d0700220e000103030e00021101100e00050d0700230e000103030e00021101110e000503010e00150d0700240e000103010e00020d0700250e000103040e00021101121200260e00030d0700270e000103030e00021101130e00050d0700280e000103030e00021101030e00050d0700290e000103040e00020c00221400010c0000140002030014000311000311000112002a274700eb110001110003131200020300480013030148002f0302480045030348005b494500be0211011411010011000111000313120001134301110001110003131500034500a011010111000111000313120001131100011100031315000345008511010211000111000313120001131100011100031315000345006a110001110003131200154700321101153a07002b264700241100024a12002c110001110003131200054a12002d110001110003131200204301430149450025110001110003131200054a12002d0211000111000313120020430211000111000313150003450003450000170003214945ff081101153a07002b2647001d1101154a12002e11000243014a12002f05000000003b0143014945000a02110116110001430149084200300349414c0146014e015a095b5c495a5c7c41454d015c09494a4144415c414d5b064b49465e495b0a5c41454d5b5c49455819085844495c4e475a451340495a4c5f495a4d6b47464b5d5a5a4d464b510c4c4d5e414b4d654d45475a51084449464f5d494f4d094449464f5d494f4d5b0a5a4d5b47445d5c4147460f495e4941447a4d5b47445d5c414746095b4b5a4d4d467c47580a5b4b5a4d4d46644d4e5c104c4d5e414b4d7841504d447a495c41470a585a474c5d4b5c7b5d4a074a495c5c4d5a510158095c475d4b4061464e47085c41454d5247464d0a5c41454d5b5c4945581a074f585d61464e470b425b6e47465c5b64415b5c0b58445d4f41465b64415b5c0a5c41454d5b5c4945581b095d5b4d5a694f4d465c0a4d5e4d5a6b474743414d075c5c775b4b414c01450b5b51465c49506d5a5a475a0c46495c415e4d644d464f5c40055a5c4b61780844474b495c414746094e587e4d5a5b4147460b77775e4d5a5b4147467777084b44414d465c614c0a5c41454d5b5c4945581c0b4d505c4d464c6e414d444c06444d464f5c40095d464c4d4e41464d4c04585d5b40044b49444403494444045c404d46', 'rewriteUrl\x20', 'setTTWid', 'height', 'product', 'Vrinda', 'X-Mssdk-Info', 'arrayBuffer', 'vibrate', 'sendBeacon', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 'canvas', 'Character\x20outside\x20valid\x20Unicode\x20range:\x200x', 'join', 'throw', 'iterator\x20result\x20is\x20not\x20an\x20object', 'DEPTH_BITS', 'compatMode', 'forEach', 'Attempted\x20to\x20access\x20private\x20element\x20on\x20non-instance', 'unsupport\x20type', 'attempted\x20to\x20call\x20addInitializer\x20after\x20decoration\x20was\x20finished', 'pageXOffset', 'length', 'method', 'bytes', 'charAt', 'Sylfaen', 'toElementDescriptor', 'base64', 'createElement', 'private', 'ttcid', 'msStatus', 'MAX_VARYING_VECTORS', 'elements', '484e4f4a403f524300232a0d2ebaf9a00000000042410a740000019d110100002347000200421101011200004700020042070001110102364700351101024a12000111010143011400011100014a120002070000430103002a34000f1100014a120002070003430103002a470002004211010333000611010312000433000911010312000412000533000c1101031200041200051200064700213e000414000c413d00171101031200041200054a1200064300082547000200424107000707000807000907000a07000b07000c07000d07000e07000f0700100700110c000b1400020700120700130700140c000314000303001400041100041100031200152747001e11000311000413140005110103110005134700020042170004214945ffd503001400061100061100021200152747002111000211000613140007110103120016110007134700020042170006214945ffd21101024a1200171101031200164301140008030014000911000814000a11000911000a1200152747003911000a1100091314000b11000b4a1200181101050700194401430133000e11010312001611000b1307001a134700020042170009214945ffba0142001b096d7f787e68736c7f68137d7f6e556d744a68756a7f686e63547b777f690773747e7f62557c09767b747d6f7b7d7f690679726875777f07686f746e73777f07797574747f796e1445456d7f787e68736c7f68457f6c7b766f7b6e7f134545697f767f74736f77457f6c7b766f7b6e7f1b45456d7f787e68736c7f6845697968736a6e457c6f74796e7375741745456d7f787e68736c7f6845697968736a6e457c6f74791545456d7f787e68736c7f6845697968736a6e457c741345457c627e68736c7f68457f6c7b766f7b6e7f1245457e68736c7f68456f746d687b6a6a7f7e1545456d7f787e68736c7f68456f746d687b6a6a7f7e1145457e68736c7f68457f6c7b766f7b6e7f144545697f767f74736f77456f746d687b6a6a7f7e1445457c627e68736c7f68456f746d687b6a6a7f7e0945697f767f74736f770c797b7676497f767f74736f771645497f767f74736f7745535e5f45487f7975687e7f6806767f747d6e72087e75796f777f746e04717f636905777b6e79720a463e417b3760477e794506797b79727f45', 'pop', 'showOffsetX', 'MAX_TEXTURE_IMAGE_UNITS', '2571598OPFKfY', 'webgl', 'appendChild', 'outerHeight', 'screenX', 'kind', 'navigator', 'attempted\x20to\x20use\x20private\x20field\x20on\x20non-instance', 'cookie', 'AsyncIterator', 'crypto', 'buffer', 'availHeight', 'The\x20property\x20descriptor\x20of\x20a\x20field\x20descriptor', 'resolve', 'react.element', 'close', 'monospace', 'stun:stun.l.google.com:19302', 'acc', 'BLUE_BITS', 'Arguments', 'style', 'nextLoc', 'pageYOffset', '72px', 'webkitRequestAnimationFrame', 'hidden', 'MAX_FRAGMENT_UNIFORM_VECTORS', 'node', 'Parchment', 'kWebsocket', 'xmst', 'number', 'altKey', 'A\x20method\x20descriptor', 'Leelawadee', '6300OtYFrs', 'href', '1155KnHwvu', 'storage', 'sTm', 'setMonth', '20690wmYtVy', '266076LNZfld', 'Malformed\x20string', 'setConfig', 'touchmove', 'rval', 'unload', 'from', 'Image', 'tryLoc', 'ActiveXObject', 'assign', '\x20property.', '_sent', 'mmmmmmmmmmlli', 'offsetHeight', 'slice', 'getOwnPropertyDescriptor', 'mhe', 'utf8', 'Object\x20is\x20not\x20async\x20iterable', 'reset', 'raw', 'constructor', 'attempted\x20to\x20', 'Invalid\x20attempt\x20to\x20iterate\x20non-iterable\x20instance.\x0aIn\x20order\x20to\x20be\x20iterable,\x20non-array\x20objects\x20must\x20have\x20a\x20[Symbol.iterator]()\x20method.', 'isArray', 'chargingTime', '__await', '484e4f4a403f524300071336bc6677450000001613b112b6000003090b4a12000911021607000a07000b4402070001430242070000140001110115082633000511011502263300071101150700012647001d3e000a140029070002140001413d000d021101001101154301140001411101013234000611010212000347000b001401010211010343004902110104430049110105120004140002110106120005140003030214000411000414000503401400060211010011011443011400071101074a120006021101001101074a1200061100074301430143011400081101074a120006021101001101074a1200061100014301430143011400091101081200071200083247001005000000003b0011010812000715000811010912000c14000a11000a33000811000a3a07000d2547000c11000a4a120008430014000a0211010a110003110002430214000b0211010b11000b11000a430214000c0211010c11000c07000e430214000d1101074a1200060211010011000d4301430114000e11010d44004a12000f43000403e81b14000f0211010e43001400101100061400111100030401001b1400121100030401001c140013110002140014110008030e13140015110008030f13140016110009030e13140017110009030f1314001811000e030e1314001911000e030f1314001a11000f03182c0400ff2e14001b11000f03102c0400ff2e14001c11000f03082c0400ff2e14001d11000f03002c0400ff2e14001e11001003182c0400ff2e14001f11001003102c0400ff2e14002011001003082c0400ff2e14002111001003002c0400ff2e140022110011110012311100133111001431110015311100163111001731110018311100193111001a3111001b3111001c3111001d3111001e3111001f311100203111002131110022311400230400ff1400240211010f11001111001311001511001711001911001b11001d11001f11002111002311001211001411001611001811001a11001c11001e11002011002243131400250211010b0211011011002443011100254302140026021101111100051100241100264303140027021101121100270700104302140028110028420011201c4c491c401b1c41401e48481a4a484c1d414048484141401d1b1e404c4a4f1d00201e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e1e010e060d1a1b171c1d071d160e1b171c1d061c1d1b171c1d09080a170c170c01081d040c0a1115070a1d0814191b1d212623240b240d3e3d3e3e2400394825530423240b240d3e3d3e3e2400394825535c011f090d0b1d0a391f1d160c060b0c0a11161f020b48071f1d0c2c11151d020b4a', 'Arial\x20Hebrew', 'msToken', 'An\x20element\x20descriptor\x27s\x20.placement\x20property\x20must\x20be\x20one\x20of\x20\x22static\x22,\x20\x22prototype\x22\x20or\x20\x22own\x22,\x20but\x20a\x20decorator\x20created\x20an\x20element\x20descriptor\x20with\x20.placement\x20\x22', 'visible', 'decode', 'concat', '30762fvQkGV', 'hash', 'STENCIL_BITS', 'configurable', '\x20private\x20field\x20on\x20non-instance', 'T_MOVE', 'clientX', 'images', 'version', 'renderer', 'removeItem', 'catchLoc', 'indexOf', 'msHidden', 'isView', 'toLocaleString', 'https://mssdk.bytedance.com', 'B4Z6wo', 'dispatchException', 'msvisibilitychange', '\x20decorators\x20must\x20return\x20a\x20function\x20or\x20void\x200', 'Dkdpgh4ZKsQB80/Mfvw36XI1R25+WUAlEi7NLboqYTOPuzmFjJnryx9HVGcaStCe', 'Cannot\x20convert\x20undefined\x20or\x20null\x20to\x20object', 'initializer', 'awrap', 'continue', 'mousedown', 'mousemove', 'update', '__ac_blank', '0123456789abcdef', 'getItem', 'Futura', 'MAX_RENDERBUFFER_SIZE', 'GPUINFO', 'host', '484e4f4a403f524300010a1106afb0650000000079a66ec20000008c1101001200004a12000143001400011100014a120002070003430103002a470002014211010307000444011400021101013300061101011200053300091101011200051200064700411101011200051200061400031100034a120002070007430103002534000f1100034a120002070008430103002534000c1100024a120009110003430147000200420142000a093b3d2b3c0f292b203a0b3a210221392b3c0d2f3d2b0727202a2b360128082b222b2d3a3c21204a10263a3a3e3d71741261126166157e637713357f627d33661260157e637713357f627d3367357d3332152f63287e637713357f627a336674152f63287e637713357f627a3367357933670822212d2f3a27212004263c2b28042827222b10263a3a3e74616122212d2f2226213d3a043a2b3d3a', 'BluetoothUUID', 'decorateClass', 'mozRTCPeerConnection', 'defineClassElement', 'credentials', 'writable', 'value', 'WEBKIT_EXT_texture_filter_anisotropic', 'JS_MD5_NO_ARRAY_BUFFER', 'Metadata\x20keys\x20must\x20be\x20symbols,\x20received:\x20', 'getReferer', 'indexDB', '__proto__', 'Object', 'splice', 'symbol', 'offsetWidth', 'executing', 'mozBattery', 'normal', 'kFakeOperations', 'reverse', 'finisher', 'createOffer', 'addEventListener', 'Cannot\x20call\x20a\x20class\x20as\x20a\x20function', '\x20must\x20be\x20a\x20function', 'getContext', 'referrer', 'afterLoc', 'has', 'return', 'kNoMove', 'netscape', 'MAX_CUBE_MAP_TEXTURE_SIZE', 'bind', 'width', 'valueOf', 'off', 'JS_MD5_NO_ARRAY_BUFFER_IS_VIEW', 'innerWidth', '257232gkndOM', 'null', 'isSecureContext', 'pixelDepth', '.initializer\x20has\x20been\x20renamed\x20to\x20.init\x20as\x20of\x20March\x202022', '/web/report', 'removeChild', '[object\x20Boolean]', 'getSupportedExtensions', 'error', 'GeneratorFunction', 'message', 'initializeInstanceElements', 'systemLanguage', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', 'tt_webid', 'sqrt', '__ac_referer', 'blocks', 'MOZ_EXT_texture_filter_anisotropic', '1hcbEHL', '308350OyvEoV', '484e4f4a403f5243003a20169967f185000000000b49c93c000000761101001200004a12000143001400011100014a120002070003430103002a47000201421101013a070004263300191101021200051200064a12000711010112000843010700092534002b1101033a0700042547000607000445000902110104110103430107000a2533000a11010312000b07000c2542000d09282e382f1c3a3833290b293211322a382f1e3c2e38073433393825123b083831383e292f323309283339383b34333839092d2f32293229242d380829320e292f34333a043e3c3131072d2f323e382e2e1006323f37383e297d2d2f323e382e2e0006323f37383e290529342931380433323938', 'for', 'break', 'construct', 'Constantia', 'webkitvisibilitychange', 'activeState', 'toClassDescriptor', 'layers', 'bogusIndex', 'arg', 'screen', 'buffer8', 'getOwnPropertyNames', 'get', 'prev', 'buildID', 'lastByteIndex', '\x27\x20method', 'Bad\x20UTF-8\x20encoding\x200x', '[object\x20Array]', 'add', '484e4f4a403f5243000027194f9666590000000044a16fed000000270700001400013e000a140002070001140001413d000d0211010011010243011400014111000142000200200d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d0d', 'call', 'characterSet', 'bodyVal2str', 'tryEntries', '\x22\x20is\x20read-only', 'tt_webid_v2', 'locationbar', 'maxTouchPoints', 'string', 'addElementPlacement', 'try\x20statement\x20without\x20catch\x20or\x20finally', 'mozVisibilityState', 'showColor', 'name', 'split', 'xmstr', 'prototype', 'AcroPDF.PDF.1', 'Tunga', '4218tDAtHd', 'AVENIR', 'getMetadata', 'track', 'touchEvent', 'decorateConstructor', 'now', 'failed\x20to\x20set\x20property', '484e4f4a403f524300263203ec75a3740000000817718683000003051100011100022e4211011507000013002547000a070001110115070002160d03000e0003000e00040c00000e00050c00000e0006010e0007010e00000700080e0002010e00090d0305033c1a0e000a03020e000b0305033c1a0e000c0e000d0700080e000e000e000f03030e00101400011101004a1200111100011101154302491100011200030300253400161101014a120012110001120003430111000112000326470009110102070013440140110001120014330007110001120015324700091101020700164401401101031200174a12001811000112000343014911010412000303002547000c1100011200031101041500031100011200043247009c110001120002070008254700091101020700194401401100011200020700012447000911010207001a44014011000112000211010415000202110105110001430111010415001b021101061101071100011200100403e81a43024911000112001c0826330005110001022647002e11010412001d4a12001811000112001c43014911010412001d4a12001e05000000003b024301323211010415001c11000112000d4700a60011010415001f11010847006411000112000d12000a33001311000112000d12000a11010412000d12000a2947003f021101091101084301491101004a1200110d11010412000d11000112000d430311010415000d0211010a11010b11010412000d12000a0403e81a43021401084500351101004a1200110d11010412000d11000112000d430311010415000d0211010a11010b11010412000d12000a0403e81a430214010811000112002047001c1100011200201101041500200211010611010c03050403e81a4302491100010b1500210211010d4300490211010e1100011200054301490211010f1100011200064301490211011043004911011132330006110001120007470020001401111100011200071101041500070211010611011203050403e81a43024911000112000f4700241101041200223247001a0011010415002202110106110113030a0403e81a11000143034900110104150023084200240350524402575a064651535d5b5a03555d50055d4767707f0e515a555658516455405c785d47400f414658665143465d405166415851470347505d0003505142035246510a415a5d4075595b415a4008415a5d40605d595105404655575f04595b5051044c4c56530450504640065547475d535a0552585b5b461e5b44405d5b5a14555d501c7d5a40515351461d145d47145a51515051501503565b5107565b517c5b474024565b517c5b474014594147401456511444465b425d505150145d5a14565b5114595b505107555d50785d4740044441475c0f4651535d5b5a145d47145a41585815124651535d5b5a145d47145d5a4255585d50150a4651535d5b5a775b5a520142106b515a55565851675d535a5540414651064651504157510b515a55565851604655575f0444514652075b44405d5b5a47046b5052440b5d5a5d405d55585d4e5150', 'appMinorVersion', 'Attempted\x20to\x20decorate\x20a\x20public\x20method/accessor\x20that\x20has\x20the\x20same\x20name\x20as\x20a\x20previously\x20decorated\x20public\x20method/accessor.\x20This\x20is\x20not\x20currently\x20supported\x20by\x20the\x20decorators\x20plugin.\x20Property\x20name\x20was:\x20', 'hex', 'dischargingTime', 'PLUGIN', 'T_KEYBOARD', 'ret_code', '\x22.\x20Please\x20configure\x20the\x20dynamicRequireTargets\x20or/and\x20ignoreDynamicRequires\x20option\x20of\x20@rollup/plugin-commonjs\x20appropriately\x20for\x20this\x20require\x20call\x20to\x20work.', '@@toPrimitive\x20must\x20return\x20a\x20primitive\x20value.', 'battery', 'Generator\x20is\x20already\x20running', 'headers', 'md5', 'setter', '=;\x20expires=Mon,\x2020\x20Sep\x202010\x2000:00:00\x20UTC;\x20path=/;', '_raw_sec_did', 'hardwareConcurrency', 'script', 'fontSize', '_byted_sec_did', 'keydown', '__private_', 'screenY', 'Duplicated\x20element\x20(', '484e4f4a403f524300211209597bcccc0000053aae77fba6000005e50b1200093247004e0b12000a4a12000b0d0700050e000c1100000e000d43014911021607000e07000f44024a120010110001430147001f1100024a12001143004a12001243004a12001307001443010300130b1500151101054a1200160b1100004302421100000b1500171101074a1200160b1100004302420c00000b15000a0b12000a4a12000b0d0700040e000c1100000e000d4301491100014a12001843000b1500191100020b15001a1101044a1200160b1100004302421101094a1200240b120019430103011d26140002021102010b12001a43013300031100024702fe0b12001a4a120024070025430103011d2947000e1101064a1200160b1100004302421100010b1500260b1200271400030b12001b1400040b12001c1400050b12001d1400060b12001e1400070b12001f1400080b1200201400090b12002114000a0d14000b030014000c11000c1101081200282747001f0b12002911010811000c131311000b11010811000c131617000c214945ffd411020212002a14000d11020212002b14000e11000e07002c2347000f07002d11020212002d0c000245001207002d11020212002d07002b11000e0c000414000f02110203021102040b12001a430111000f4302140010021102051100104301140011021102061100110b1200264302140012021102031100101101011100120c0002430214001307002c14001411020712002e4700091100131400144500910d021102080211001343020e002f1400150b12001907002325470050021102090b120015430147003a0211020a1100150b1200150b1200264303490211020b110015080700304303140016021102031100131101021100160c000243021400144500061100131400144500250211020b110015080700304303140017021102031100131101021100170c000243021400140b12000a33000f0b12000a03001307000c130700042647000202420b12000a14001803001400191100191100181200282747005d11001903002547002d1100141100181100191312000d030116000b1500091101044a1200160b1100181100191312000d43024945001f0b1100181100191307000c13134a1200160b1100181100191312000d430249170019214945ff960b1200174700100b1200074a1200160b0b1200174302490b07000a39491102071200314700140b4a12000511020c1200320211020d43004302491100030b1500271100040b15001b1100050b15001c05000003ed3b010b15001d1100070b15001e1100080b15001f1100090b15002011000a0b150021030014001a11001a1101081200282747001f11000b11010811001a13130b12002911010811001a131617001a214945ffd41101064a1200160b11000043024203001400020b1200333400040b12001a34000307002c1400030211030e110003430147000503011400021100034a120024110300120034120035430103011d2647000503021400021100020300294700ea0b4a12003607003743011400041100044700d70211030f0b12001a43011400051100051103101200382547005511000411030215002d11000511030215002a0211031107002d1100044302490211031211000443014911000511010d2947001f1103021200391200280300294700100211031311031403020403e81a43024945001611010d11030212002a2a47000911000411030215002d11010d11031012003a2533000c110302120039120028030a274700361103021200394a12000b110004430149110302120039120028030125470017021103121100044301490211031107002d11000443024911010647000a02110106110001430149084207000014000107000114000211010012000212000314000311000312000414000411000312000514000511000312000614000611000312000714000711000312000847000208420011000315000805000000003b0211000315000505000000643b0011000315000705000000793b0211000315000407001b07001c07001d07001e07001f0700200700210c00071400080700220700230c000214000905000000ba3b011100031500060842003b0755204f626a787e0a527e646a636c79787f680e5540414579797d5f687c78687e79097d7f62796279747d6804627d6863107e68795f687c78687e7945686c69687f047e68636910627b687f7f6469684064606859747d680f526c6e52646379687f6e687d79686905527e68636915526f7479686952646379687f6e687d795261647e79047d787e65046b78636e096c7f6a78606863797e0e536e6263796863792079747d682901640479687e790879625e797f64636a0b796241627a687f4e6c7e68057e7d61647901360e526f74796869526e626379686379056c7d7d61741552627b687f7f6469684064606859747d684c7f6a7e0b7962587d7d687f4e6c7e680d526f74796869526068796562690a526f7479686952787f610762636c6f627f79076263687f7f627f06626361626c6909626361626c696863690b626361626c697e796c7f790a62637d7f626a7f687e7e09626379646068627879034a4859045d425e59076463696875426b0b527e646a636c79787f68300b526f74796869526f6269741262637f686c69747e796c79686e656c636a68066168636a796506787d61626c6908607e5e796c79787e0b52526c6e5279687e7964690007607e5962666863017b03787f61076b627f7f686c61037e69640d7e686e44636b6245686c69687f0b7f687e7d62637e68585f410861626e6c796462630465627e79116a68795f687e7d62637e6845686c69687f0a7520607e207962666863037e686e0e607e43687a596266686341647e790464636479', 'round', 'innerHTML', 'appCodeName', 'defineProperties', 'Could\x20not\x20dynamically\x20require\x20\x22', 'push', '__destrObj', 'toElementDescriptors', 'defaultProps', 'fromElementDescriptor', 'documentMode', 'Object.keys\x20called\x20on\x20non-object', 'WEBGL_debug_renderer_info', 'reduce', 'replace', 'setUserMode', 'changedTouches', 'JS_MD5_NO_WINDOW', '[object\x20Object]', 'item', 'beforeunload', '%27', 'enableTrack', 'envcode', 'gpu', 'ubcode', 'getParameter', 'undefined', 'start', 'isGeneratorFunction', 'completion', 'getOwnPropertySymbols', 'next', 'availWidth', 'values', 'oscpu', 'Tw\x20Cen\x20MT', 'sort', 'bluetooth', 'requestMediaKeySystemAccess', 'keyboardList', 'key', 'window', 'Unfinished\x20UTF-8\x20octet\x20sequence', 'setMetadata', 'static', 'debug', 'languages', 'toolbar', 'msDoNotTrack', 'reject', 'finishers', '208XZrBOJ', 'UNMASKED_RENDERER_WEBGL', 'external', 'shadowBlur', 'POST', '484e4f4a403f5243003e0d23e5c579310000006248d1745c000002cc0d140001110200070000131400021100020700012447000a11000211000107000016110200070002131400031100030700012447000a11000311000107000316110200070004131400041100040700012447000a110004110001070005161100014205000000003b001400010114000211010f3247000911010112000614010f11010f110101120007254700040014000211010244004a12000843001400030d1101001200094a12000a030043010e000b11010012000c4a12000a030043010e000d11010012000e4a12000a030043010e000f1101001200104a12000a030043010e001114000411000412000b12001203002533000c11000412000d12001203002533000c11000412000f12001203002533000c110004120011120012030025470002084211000412000b12001203101a11000412000d120012030c1a1811000412000f12001203041a1811000412001112001203081a181400051100031101031200131101041200141200150403e81a182747003a1101031200161101041200141200170404001a27470020110103120016110005181101030700163549021101054300490014000245000045001d11000311010315001311000511010315001602110105430049001400021100024700f703021400060d1100040e00181100060e00191400070d11000707001a1611010412001b11000707001a1307001b1607000111010244004a12000843001811000707001a1307001c1611010012001d11000707001a1307001d16030011000707001a1307001e160d11000707001f161101064a12002011000707001f13021100014300430249021101071101081200210211010911010a4a120022110007430111010b120023430243021400081101041200240700251314000911000932470002084211010f110101120026254700190211010c110009110008430214000a11000a3247000045000f0211010d1100091100080d0043044908420027052121223c31000821210a2230373c310721210230371c310b21210a2230373c310a23670921210230373c3103670727203b3b3c3b3205333920263d07323021013c383008383a2330193c2621062625393c3630063730183a23300936393c363e193c262107373016393c363e0c3e302c373a342731193c26210a37301e302c373a3427310b3436213c233006213421300b223c3b313a2206213421300639303b32213d0326013805212734363e08203b3c21013c3830033436360a203b3c2114383a203b210837303d34233c3a2707382632012c253003221c1103343c3109213c3830262134382507343c31193c26210b25273c2334362c183a313006362026213a38063426263c323b0f0210170a1110031c16100a1c1b131a092621273c3b323c332c043f263a3b0a2730323c3a3b163a3b33092730253a272100273904302d3c21', 'metadata', 'productSub', 'mark', '\x20is\x20not\x20an\x20object.', 'substr', 'Invalid\x20attempt\x20to\x20spread\x20non-iterable\x20instance.\x0aIn\x20order\x20to\x20be\x20iterable,\x20non-array\x20objects\x20must\x20have\x20a\x20[Symbol.iterator]()\x20method.', 'Gulim', 'experimental-webgl', 'setRequestHeader', 'charging', '484e4f4a403f52430031032581faca6c0000000093505d60000001c60700001400010d1400020700011100020700021607000311000207000416070005110002070006161100021101021314000307000714000403001400061101011200081100060303182a4700b11101014a1200091700062143010400ff2e03102b1101014a1200091700062143010400ff2e03082b2f1101014a1200091700062143010400ff2e2f1400051100041100034a12000a1100050500fc00002e03122c43011817000435491100041100034a12000a110005050003f0002e030c2c43011817000435491100041100034a12000a110005040fc02e03062c43011817000435491100041100034a12000a110005033f2e430118170004354945ff3f110101120008110006190300294700b41101014a1200091700062143010400ff2e03102b110101120008110006294700161101014a12000911000643010400ff2e03082b45000203002f1400051100041100034a12000a1100050500fc00002e03122c43011817000435491100041100034a12000a110005050003f0002e030c2c4301181700043549110004110101120008110006294700161100034a12000a110005040fc02e03062c430145000311000118170004354911000411000118170004354911000442000b011441686b6a6d6c6f6e616063626564676679787b7a7d7c7f7e717073484b4a4d4c4f4e414043424544474659585b5a5d5c5f5e51505319181b1a1d1c1f1e1110020614025a19416d424d594e411d73625a786b111906644f5f5e1a1f7160187b1b1c027e7c68456c401e67654b4658707d66795c53446f4363475b505110617f6e4a487a5d6a4c14025a18416d424d594e411d73625a786b111906644f5f5e1a1f7160187b1b1c047e7c68456c401e67654b4658707d66795c53446f4363475b505110617f6e4a487a5d6a4c14025a1b0006454c474e5d410a4a41485b6a464d4c685d064a41485b685d', 'toString', 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx', 'warn', 'parse', 'sent', 'iterator', 'PDF.PdfCtrl.', '__ac_testid', 'clickList', 'create', 'hasOwnProperty', 'init', 'An\x20initializer', 'clientHeight', 'extras', '__esModule', 'sessionStorage', 'kKeyboardFast', 'devicePixelRatio', ';\x20path=/;', 'location', 'GREEN_BITS', '484e4f4a403f524300192d11257a6fc000000000d4cf00750000006703011400011101004a12000011010603062b1100012f43011400021101004a1200001101014a1200011101014a12000243000401001a4301430114000302110102110003110105430214000411000211000318110004181400050211010311000507000343024200040c5f4b56547a51584b7a565d5c055f5556564b064b58575d5654024a08', 'Castellar', 'toGMTString', 'mozHidden', 'Set', '[native\x20code]', 'complete', '484e4f4a403f52430012270f0b8aa329000000005cddda270000008a0211010043003247007e1101014a12000007000143011400011100011200024a12000343004a120004110104070005070006440207000743024a120008070009430103002734002c1101021200034a12000343004a120004110104070005070006440207000743024a120008070009430103002734001011010212000a4a120003430007000b26420142000c0d18091e1a0f1e3e171e161e150f06181a150d1a08090f143f1a0f1a2e2937080f14280f0912151c07091e0b171a181e03270851011c000712151f1e03341d0a151a0f120d1e18141f1e070b170e1c12150814201419111e180f5b2b170e1c12153a09091a0226', 'filter', 'runClassFinishers', 'webkitVisibilityState', '2.11.0', '\x20after\x20decoration\x20was\x20finished', 'suffixes', 'completed', 'src', 'Cannot\x20instantiate\x20an\x20arrow\x20function', 'getTime', 'resultName', 'children', 'accessor.get', '484e4f4a403f52430024153c4037f00000000009d722c1e5000000d200110208150002084202110100430047001c1101014a120000070001430114000105000000003b001100011500030211010243004700553e002b140002110002120004110104070005132533000c11010312000612000703002547000700110108150002413d00241101031200064a12000807000907000a4302491101031200064a12000b0700094301494102110105430047002311010312000c3233000f11010312000d34000611010312000e4700070011010815000211010612000f11010812000203022b2f11010607000f35490842001004637c69620478697f780965626f636b62657863076362697e7e637e046f636869125d5943584d5349544f494948494853495e5e0e7f697f7f6563625f78637e6d6b69066069626b7864077f697845786961107f63616947697544697e694e75786968000a7e6961637a69457869610965626869746968484e0c5c63656278697e497a6962780e415f5c63656278697e497a6962780769627a6f636869', 'https://mssdk.bytedance.com/websdk/v1/getInfo', '?q=', '484e4f4a403f5243003e19390bcd41790000000084fc29f10000006111010012000033000d1101001200001200010700022347000303014211010112000311010112000412000326470003030142110101120005110101120006264700030301421101011200071200081101021200071200082447000303014203024200090c3125363a32123b323a3239230723363019363a32061e1105161a12083b383436233e3839062736253239230424323b3103233827063125363a3224063b323930233f', 'defineProperty', '[object\x20Generator]', 'Wingdings', 'hasInstance', 'SHADING_LANGUAGE_VERSION', 'platform', '484e4f4a403f52430007152cc2c1a53c00000061235466970000007f1100010700022534000711000107000325340007110001070004253400071100010700052547000200423e0004140002413d002b1102021100011333001b11020211000113120006082634000c11020211000113120007082647000200424108421101014a12000011010243014a12000105000000003b0143011401000842000813717362596178466479667364626f58777b73650465797b7308757370457e77646608557370457e77646605737977667f16737941737454647961657364527f65667762757e73640f747f787259747c73756257656f78750e7f65535941737454647961657364', 'asyncIterator', 'object', 'colorDepth', 'keys', 'wrapped', 'getter', 'finalized', 'all', 'appName', 'regionConf', 'application/x-www-form-urlencoded', 'attempted\x20to\x20get\x20private\x20field\x20on\x20non-instance', 'createEvent', 'body', 'toElementFinisherExtras', 'open', 'displayName', '_urlRewriteRules', 'random', 'font', '484e4f4a403f52430031033191576c4000000000940c5eb50000005302110100430032470047070000110101363234000b110101120000110102373234000707000111010336340007070002110103363400070700031101033634000f0700041101033607000511010336274201420006077d61786a64637e08527d656c637962600b6e6c61615d656c637962600b525263646a6579606c7f68054c78696462184e6c637b6c7e5f686369687f64636a4e6263796875793f49', 'discharingTime', 'SimSun-ExtB', 'fromClassDescriptor', 'versions', 'charCodeAt', 'fillText', 'fetch', 'freeze', 'Create\x20WebSocket', 'webkitRTCPeerConnection', 'digest', 'class', 'MAX_VERTEX_UNIFORM_VECTORS', 'filename', 'first', 'visibilitychange', 'A\x20class\x20descriptor', 'clientWidth', 'frontierSign', 'msVisibilityState', 'antialias', '484e4f4a403f5243002a3d04fa03273900000000b93145d7000004061101001200004a12000143001400011101001200024a120001430014000203001400030301140004030214000503031400060304140007030514000811000814000907000314000a07000414000b07000514000c07000614000d07000714000e07000814000f07000914001007000a1400111100014a12000b07000c430103002a34000f1100014a12000b07000d430103002a4700091100071400094500de1100014a12000b11000a430103002a4700091100031400094500c31100014a12000b11000c430103002a4700091100041400094500a81100014a12000b11000d430103002a34000f1100014a12000b07000e430103002a34000f1100014a12000b07000f430103002a4700091100051400094500691100014a12000b11000e430103002a34000f1100014a12000b11000f430103002a34000f1100014a12000b110010430103002a34000f1100014a12000b070010430103002a34000f1100014a12000b070011430103002a4700091100061400094500061100081400091100024a12000b11000b430103002a33000711000911000326470005004245012c1100024a12000b11000d430103002a34000f1100024a12000b11000c430103002a34000f1100024a12000b070012430103002a330007110009110005263300071100091100042647000500424500dd1100024a12000b110011430103002a34000f1100024a12000b11000f430103002a34000f1100024a12000b110010430103002a34000f1100024a12000b11000e430103002a3300071100091100072633000711000911000626470005004245007c1100024a12000b11000b430103002733000f1100024a12000b11000d430103002733000f1100024a12000b110011430103002733000f1100024a12000b11000e430103002733000f1100024a12000b11000f430103002733000f1100024a12000b1100104301030027140012110012110009110008252647000200420300140013030114001403021400150303140016030414001703051400181100181400191100014a12000b070013430103002a47000911001514001945008a1100014a12000b070014430103002a34000f1100014a12000b070015430103002a34000c1100014a12000b070016430147000911001414001945004e1100014a12000b070017430103002a4700091100131400194500331100014a12000b070018430103002a34000f1100014a12000b070019430103002a4700091100171400194500061100181400190211010143004a120001430014001a110019110013243300071100191100142433002111010212001a34001811010012001b4a12001c43004a12000b07001d430103002a4700020042110019110013243300071100191100142433000f11001a4a12000b07001a430103002a47000200420142001e090b0d1b0c3f191b100a0b0a113211091b0c3d1f0d1b080e121f0a18110c13070917101a11090d03091710071f101a0c11171a051217100b0606170e1611101b04170e1f1a04170e111a03131f1d0717101a1b06311809131f1d17100a110d160c131f1d210e11091b0c0e1d57041d0c110d03064f4f051d0c17110d05180617110d040e17151b0818170c1b1811065106110e1b0c1f51055e110e0c51055e110e0a51071d160c11131b51080a0c171a1b100a5104130d171b061d160c11131b06081b101a110c080a112d0a0c1710190639111119121b', 'setTTWebid', 'Buffer', '_enablePathListRegex', 'outerWidth', 'type', 'decorateElement', '484e4f4a403f524300040e131c85d3950000064d665eaab9000007ca05000001d03b0014000105000003953b00140002050000046a3b001400031102084400140004021100024300490211000343004907004b07004c07004d07004e07004f07005007005107005207005307005407005507005607005707005807005907005a07005b07005c0c001214000702110209110200110007030043031400051100050211020911020007005d1307005e0c000111000712005f43032f17000535490700600c00011400080211020911020607006113110008030043031400060d1400090211020a4300110009070062160211020b4300110009070063160211020c43001100090700641607001811020844004a1200654300181100090700661611020d4a1200671100044a12006843001d033c1b4301110009070069160211020e430011000907006a160211020f43004a120008430011000907001d1611000511000907006b1611000611000907006c1602110210430011000907006d1602110001430011000907006e1602110211430011000907006f16030114000a11021212007011000907007016021102130700714301110009070072160211021307007343011100090700741611000a1100090700751603001100090700761611021412007711000907007716110009423e000714000a030042413d01b6030014000111030007000013340014110301070001134a07000213070003430103002a47000607000445000203001400020700051103023a24470006070006450002030014000311030307000713070008134a0700091311030007000a1343014a0700021307000b430103002934002e11030007000c1333000b11030007000c1307000d1333001607000e11030007000c1307000d134a0700081343002534000711030007000f131400041100044700060700104500020300140004110004330011110301070001134a0700111307001243014700060700134500020300140005110300070014133300041100023247000607001545000203001400060211030443001400071100073233000711030007001613470006070017450002030014000807001814000911000247000b11000103012f170001354911000347000e110001030103012b2f170001354911000847000e110001030103022b2f170001354911000747000e110001030103032b2f170001354911000647000e110001030103042b2f170001354911000547000e110001030103052b2f170001354911000447000e110001030103062b2f17000135491100014241084211030512001907001a133247000c030011030512001907001a163e0010140003030111030512001907001a16413d004911030007001b1347003e11030007001b1344001400011103064a07001c1307001d43014a07001e1307001f430114000205000004103b0011000107002316070024110001070025164108423e0010140002030111040512001907001a16413d00421101024a070020131101010300030043034903001101024a0700211303000300030103014304070022130303132514000103021100011811040512001907001a164108420c000014000107002607002707002807002907002a07002b07002c07002d07002e07002f0700300700310700320700330700340700350700360700370700380700390c001414000211030107003a133247000e07003b11030512001907003c35423e001214000507003d11030512001907003c3542413d003b05000005203c021400031100024a0700481305000005c63b0243011400041103074a0700491311000443014a0700401305000005d33b0043014941084211050107003a134a07003e130d1100010e003f43014a0700401305000005523b0143014a07004513050000059e3b014301421100010700411307004248001007004348001607004448001c49450024030111030111010216450021030211030111010216450015030011030111010216450009030511030111010216084203011d110001070046134a0700021307004743012647000503044500020303110301110102160842021101031100011100024302421101014a07004a13070018430111040512001907003c35420d140001110214070078131400021100020700182447000a11000211000107007816110214070079131400031100030700182447000a11000311000107007a1611021407007b131400041100040700182447000a11000411000107007c161100014205000000003b0014000105000005eb3b0014000202110115430049021101164300490211011743004902110118430049021101194300491101034a12007d1101051200190211000143004302491101034a12007d11010512007e0211011a43004302491101034a12007d11010512007f0211011b43004302491101034a12007d1101051200800211000243004302491101141200814a120082030043011400030d1100030e00831400040700841400050211011c0211011d1100054301030a430214000611000647000e110006030118170006354945000503011400060211011e11000511000643024911000611010507001913070085161101034a12007d1100041101054302490211011f1101204a1200861100044301110121120087430214000702110122110123120088110007430214000811011212008907008a1314000911000932470002084211012447001b1101244a120040021101251100091100080d00430443014945000f021101251100091100080d004304490842008b051b0411061509010711063513111a00071d1a10110c3b1205543b24265b053b0411061509011a1011121d1a111007321d0611121b0c0904061b001b000d041108001b2700061d1a1304171518180b3c20393831181119111a000b371b1a0700060117001b060607151215061d100401071c3a1b001d121d1715001d1b1a212f1b161e1117005427151215061d2611191b00113a1b001d121d1715001d1b1a290f350404181124150d271107071d1b1a0627151215061d05191500171c0537061d3b270a371c061b1911543d3b2706171c061b191106371c061b19110a27000d18113911101d1504311013110003033d3004181b1510053d191513110d17061115001131181119111a000617151a0215070a131100371b1a00110c0002461009100615033d191513110c1311003d19151311301500150410150015061b1a181b15104e101500154e1d191513115b131d124f16150711424058264418333b30181c35253536353d35353535353535245b5b5b0d3c41363531353535353538353535353535363535313535353d3626353543030706170b13111b181b1715001d1b1a0d1a1b001d121d1715001d1b1a07040401071c04191d101d061715191106150a191d17061b041c1b1a1107070411151f11060b1011021d1711591d1a121b0f1615171f13061b011a1059070d1a170916180111001b1b001c12041106071d0700111a005907001b06151311141519161d111a0059181d131c005907111a071b060d151717111811061b191100110609130d061b07171b04110c1915131a11001b19110011060917181d04161b150610141517171107071d161d181d000d591102111a00070e17181d04161b15061059061115100f17181d04161b1506105903061d00110f04150d19111a00591c151a101811060b041106191d07071d1b1a070142031a1504014305050111060d041a15191104001c111a0507001500110604061b190400071306151a0011100610111a1d111005171500171c0719110707151311301d07541a1b005415540215181d1054111a0119540215180111541b1254000d041154241106191d07071d1b1a3a1519110319150403151818041e1b1d1a0e2c301b19151d1a261105011107000b170611150011241b040104130611191b02113102111a00381d0700111a11060d13181b16151827001b061513110c1b04111a3015001516150711091d1a10110c111030360b15000015171c3102111a000d3517001d02112c3b161e1117000d101d07041500171c3102111a000b15101036111c15021d1b06101510103102111a00381d0700111a11060b10110015171c3102111a0009121d06113102111a001039010015001d1b1a3b16071106021106133c20393839111a013d00111931181119111a00093d1a004c350606150d0b041b0700391107071513110d050111060d2711181117001b060b041106121b0619151a1711031a1b030618111a13001c0b171b1a00110c0039111a010f101b170119111a0031181119111a000c1a15001d021138111a13001c0b1e07321b1a0007381d07000b070d1a00150c3106061b0607131100201d191109001d191107001519040512181b1b0611131100201d19110e1b1a113b121207110008001d19110e1b1a11051915131d17060324061b0407061024061b0407031e07020b16061b03071106200d0411061d120615191103151d10050000171d100617181d111a000700002b07171d1005001b1f111a07190713200d04110b04061d0215170d391b101107151d10381d0700050000031d100800002b0311161d100700002311163d100b00002b0311161d102b02460900002311161d102246061507071d131a07041801131d1a070607170611111a06170107001b190e19073a1103201b1f111a381d0700060704181d171109001b1f111a381d0700040c19071d051d1a10110c090700061d1a131d120d041e071b1a0f2331362b3031223d37312b3d3a323b0a0611131d1b1a371b1a12090611041b0600210618', 'dev', '[object\x20Function]', 'substring', '_invoke', 'getBattery', 'boeHost', 'asgw', 'Generator', 'boe', 'decorators', 'exports', 'accessor', 'plugins', 'this\x20hasn\x27t\x20been\x20initialised\x20-\x20super()\x20hasn\x27t\x20been\x20called', 'delegate', 'attempted\x20to\x20set\x20read\x20only\x20static\x20private\x20field', 'callback=', 'MAX_TEXTURE_MAX_ANISOTROPY_EXT', 'toStringTag', ';\x20expires=', 'match', 'root', 'setItem', 'getContextAttributes', 'withCredentials', 'Class\x20\x22', 'mozvisibilitychange', 'userLanguage', 'createHash', 'map', 'Cannot\x20destructure\x20', 'hBytes', '[object\x20Number]', 'floor', 'access', '484e4f4a403f5243001a3309b621c6a00000000048c0ec7f000000650d14000111010012000047000c1101001200001400014500090211010143001400011101024a1200014300110001150002021101030304430114000211000202110104021101051101064a12000311000143011100024302070004430218140003110003420005077563656f6860690348495109524f4b435552474b56095552544f48414f405f40676465626360616e6f6c6d6a6b686976777475727370717e7f7c474445424340414e4f4c4d4a4b484956575455525350515e5f5c16171415121310111e1f0b08', 'MAX_COMBINED_TEXTURE_IMAGE_UNITS', 'default', 'public', 'vendorSub', 'touchstart', 'getExtension', 'Aparajita', 'finalize', 'propertyIsEnumerable', 'end', 'localStorage', '@@iterator', 'deviceMemory', 'kHttp', '@@toStringTag', 'cookieEnabled', 'fromCharCode', 'done', 'set', 'createDataChannel', 'stringify', 'async', 'Descriptor', 'hashed', 'ontouchstart', 'onicegatheringstatechange', 'getOwnPropertyDescriptors', 'then', 'function', 'CordiaUPC', 'T_CLICK', 'EXT_texture_filter_anisotropic', 'MS\x20Outlook', '80pSJSjK', 'Jokerman', 'byted_acrawler', 'visibilityState', 'span', 'isWebmssdk', '__web_idontknowwhyiwriteit__', 'cpuClass', 'serif', 'initialized', 'accessor\x20decorators\x20must\x20return\x20an\x20object\x20with\x20get,\x20set,\x20or\x20init\x20properties\x20or\x20void\x200', '[object\x20HTMLAllCollection]', 'Decorating\x20class\x20property\x20failed.\x20Please\x20ensure\x20that\x20proposal-class-properties\x20is\x20enabled\x20and\x20runs\x20after\x20the\x20decorators\x20transform.', '\x27\x20to\x20be\x20a\x20function', 'VERSION', 'toLowerCase', 'MAX_TEXTURE_SIZE', 'triggerUnload', 'MAX_VERTEX_TEXTURE_IMAGE_UNITS', 'element', 'apply', 'document', 'exec', 'send', ')\x20can\x27t\x20be\x20decorated.', 'min', '484e4f4a403f5243002814122ddd79950000009eb285a1cb000000e811000114000402110201110001430147007c1102021200041400051100050700052347000f0700061102021200060c00024500120700061102021200060700041100050c0004140006021102030211020411000143011100064302140007021102051100074301140008021102061100080700054302140009021102031100071101011100090c000243021400040211010211000411000211000343034205000000003b03140003070000140001110100120001082334000611010012000247000208421101001200011400021100021101001500030011010015000211000311010015000108420007070d78173a322026043a25303b150a0a34360a3c3b2130273630252130310a3a25303b050a3a25303b0b0a0a34360a213026213c3100073826013a3e303b', 'vivobrowser', 'descriptor', 'language', '484e4f4a403f524300023a25866a0150000000002b0aa01b000001541101001200004a12000143001400011100014a120002070003430103002a47000201420700041400021101013a070004254700060700044500090211010211010143011100022534000d1101014a1200054300070006263400161101031200071200054a12000811010143010700062634001e1101043a07000425470006070004450009021101021101044301110002253400151101044a12000543004a120002070009430103002734001e1101003a070004254700060700044500090211010211010043011100022534000d1101004a120005430007000a263400121101001200004a12000207000b430103002a34001e1101053a07000425470006070004450009021101021101054301110002254700020042021101064300324700331101073a070004254700060700044500090211010211010743011100022534000d1101074a120005430007000c2647000200420142000d096f697f685b7d7f746e0b6e7556756d7f68597b697f0773747e7f62557c087f767f796e687574096f747e7f7c73747f7e086e75496e6873747d0f417578707f796e3a4d73747e756d47096a68756e756e636a7f04797b7676085e75796f777f746e12417578707f796e3a547b6c737d7b6e7568470570697e757710417578707f796e3a5273696e75686347', 'vendor', 'level', 'attempted\x20to\x20call\x20', 'placement', 'JS_MD5_NO_NODE_JS', 'initializeClassElements', 'indexedDB', 'perf', 'disallowProperty', 'lime', '484e4f4a403f524300341b3e336a785800000000dbd5951f000001b50114000111010012000000254700070014000145001b1101001200000125470007011400014500090211010143001400010d010e0001010e0002010e00031100010e0004010e0005010e0006010e0007010e0008010e0009010e000a010e000b000e000c1400020211010243001100021500051100021200053247005c021101031100024301490211010411000243014902110105430011000215000702110106430011000215000802110107430011000215000902110108430011000215000b0211010943001100021500030211010a4300110002150002030014000311000303012f170003354911000311000212000b03012b2f170003354911000311000212000a03022b2f170003354911000311000212000903032b2f170003354911000311000212000803042b2f170003354911000311000212000703052b2f17000335491100031100020700061303062b2f170003354911000311000212000503072b2f17000335491100031100020700041303082b2f170003354911000311000212000303092b2f1700033549110003110002120002030a2b2f170003354911010b12000d1100032f11010b07000d354911000242000e0e547b6a796a66587c627f686344650a6f62796e687f58626c650a6864657862787f6e657f086764686a7f62646506787c627f6863036f6466086f6e697e6c6c6e790465646f6e077b636a657f6466097c6e696f79627d6e7909626568646c65627f640463646460047f6e787f076e657d68646f6e', 'moveList', 'MYRIAD\x20PRO', 'An\x20element\x20descriptor', 'finallyLoc', 'head', 'innerHeight', 'ORIGIN:\x20', 'region', 'addInitializer', '[object\x20SafariRemoteNotification]', 'candidate', 'content-type', 'userAgent', 'webkitHidden', 'test', 'getPrototypeOf', 'setDate', 'shiftKey', 'accessor.init', '@@asyncIterator', 'accessor.set' ] w_0x42f5 = function () { return _0x458f30 } return w_0x42f5() } function w_0x5c3140(_0x41676a, _0x3f9548, _0x39b0b8) { var _0x2145df = w_0x25f3 function _0x467cb0(_0x174e0d, _0x4ea737) { var _0x569e4c = w_0x25f3, _0x3ed868 = parseInt( _0x174e0d[_0x569e4c(0x2a5)](_0x4ea737, _0x4ea737 + (0x30 * 0x1a + 0x1 * 0x1424 + -0xc2 * 0x21)), -0x253b + -0x1ce1 + -0x974 * -0x7 ) return _0x3ed868 >>> (0x23ca + 0x882 + 0x2c45 * -0x1) == 0x11cb + -0x5c7 * 0x3 + 0x2 * -0x3b ? [-0xc * 0x300 + 0x1 * 0x1067 + 0x139a, _0x3ed868] : _0x3ed868 >>> (-0x3 * 0x3b9 + 0x4a * 0x75 + -0x16a1) == -0x742 + -0x429 + 0xb6d ? ((_0x3ed868 = ((-0x1eee + 0x1175 + 0xdb8) & _0x3ed868) << (0x2 * 0x108d + 0x2 * -0x5e6 + 0x1 * -0x1546)), [ -0x949 + 0xe2f + -0x4 * 0x139, (_0x3ed868 += parseInt( _0x174e0d['slice'](_0x4ea737 + (0x5 * -0x643 + -0x1 * 0x95 + -0x1fe6 * -0x1), _0x4ea737 + (0x9b6 + 0x8 * 0x24a + -0x1c02)), -0xa6 * 0x11 + -0x3f * -0x1 + 0x6f * 0x19 )) ]) : ((_0x3ed868 = ((0x1af1 + 0x1442 + -0x964 * 0x5) & _0x3ed868) << (0x3f3 + -0xd93 + 0x9b0)), [ -0x13 * -0x192 + -0x1588 + 0xc1 * -0xb, (_0x3ed868 += parseInt( _0x174e0d[_0x569e4c(0x2a5)]( _0x4ea737 + (-0x8 * 0x39c + 0x59 * 0x35 + 0x1 * 0xa75), _0x4ea737 + (0x1 * -0xad6 + -0x326 + 0x16 * 0xa3) ), 0x20b0 + -0x7d + -0x1b1 * 0x13 )) ]) } var _0x450bf1, _0x55d729 = 0x242c + 0x150c * 0x1 + -0x4 * 0xe4e, _0x26f45f = [], _0x408609 = [], _0x5e254d = parseInt( _0x41676a[_0x2145df(0x2a5)](-0x43 * 0x7a + 0xbac * -0x1 + 0x2 * 0x15cd, -0x18c6 + -0x1515 + 0x2de3), -0x17e6 + 0x4 * -0x269 + 0x1fa * 0x11 ), _0x56844b = parseInt( _0x41676a[_0x2145df(0x2a5)](0x262 * -0x3 + 0x19e0 + -0x12b2, 0x5 * 0x3e + 0xd * -0x2ec + -0x73 * -0x52), 0x1 * 0xd69 + 0x1 * 0xb9 + -0xe12 ) if (-0x5eec40a * 0xd + 0x353b2368 + 0x60332064 !== _0x5e254d || 0x7b7 * 0x44245 + -0x712c7271 + 0x1ce9b3ad * 0x5 !== _0x56844b) throw new Error(_0x2145df(0x2a7)) if ( 0x2 * 0xae1 + -0x1e47 + 0x885 !== parseInt( _0x41676a[_0x2145df(0x2a5)](0x1 * 0x45 + 0x149 * -0x1 + 0x114, -0x1d69 * -0x1 + 0xf47 * 0x1 + -0x2c9e), -0x59 * 0x4b + -0xfdb + -0xd7 * -0x32 ) ) throw new Error('ve') for (_0x450bf1 = 0x2 * 0xe7d + -0xdf * -0x19 + 0x3d * -0xd5; _0x450bf1 < -0x22db * -0x1 + -0xf98 * -0x1 + -0x1 * 0x326f; ++_0x450bf1) { _0x55d729 += ((-0x1a7 * 0x3 + 0x17 * -0x47 + 0xb59) & parseInt( _0x41676a[_0x2145df(0x2a5)]( 0x751 * -0x4 + 0x1d * 0xfd + 0xb3 + (-0x44b * 0x7 + -0x100 + 0x1f0f) * _0x450bf1, 0x8 * 0x3ae + 0x128d + -0xd * 0x3af + (0x2 * -0x80f + -0xd * 0x24a + 0x2de2) * _0x450bf1 ), -0x14d6 + -0x255 + 0x173b )) << ((-0x1ce2 * -0x1 + 0x11e3 + -0x2ec3) * _0x450bf1) } var _0x537efa = parseInt( _0x41676a[_0x2145df(0x2a5)](0x13 * -0x209 + 0x116b + 0xc * 0x1c8, -0x26a0 + 0x10d * -0x12 + 0x39b2), 0x154e + -0x25e * -0xf + 0xe3 * -0x40 ), _0x3d66d8 = (0x1bdb * 0x1 + -0x4e9 * 0x3 + -0xd1e) * parseInt( _0x41676a[_0x2145df(0x2a5)](-0x1 * -0x24f5 + 0x2279 + 0x67a * -0xb, -0x2 * -0x1083 + -0x5 * 0x185 + 0xef * -0x1b), -0x82 + 0x8e6 + 0x4 * -0x215 ) for ( _0x450bf1 = -0x2471 + -0x116 * -0x7 + 0x1d0f * 0x1; _0x450bf1 < _0x3d66d8 + (-0x1c * -0x106 + 0x370 + -0x8 * 0x3fc); _0x450bf1 += 0x13ac * 0x1 + 0x9bd * 0x1 + -0x1 * 0x1d67 ) _0x26f45f[_0x2145df(0x36e)]( parseInt( _0x41676a[_0x2145df(0x2a5)](_0x450bf1, _0x450bf1 + (0x7 * 0x539 + 0x3cb * -0x2 + -0x1 * 0x1cf7)), 0x23fc + -0xa45 + -0x3 * 0x88d ) ) var _0x50f001 = _0x3d66d8 + (-0x1429 + -0x69d * -0x1 + 0x371 * 0x4), _0x23f32e = parseInt( _0x41676a[_0x2145df(0x2a5)](_0x50f001, _0x50f001 + (-0x179c + -0x3f + -0x61 * -0x3f)), -0x2a * 0x65 + -0x20e5 + 0x3187 ) for (_0x50f001 += -0x20c6 + 0x3 * -0x1a5 + 0x25b9, _0x450bf1 = -0x2 * -0x766 + 0x127e + -0x214a; _0x450bf1 < _0x23f32e; ++_0x450bf1) { var _0x37a7c1 = _0x467cb0(_0x41676a, _0x50f001) _0x50f001 += (0xcfd + 0x399 * -0x3 + -0x7 * 0x50) * _0x37a7c1[-0x14ee + -0x912 + 0x1e00] for ( var _0x13d988 = '', _0x4b0c3a = -0x1bcf + 0x16cf + 0x10 * 0x50; _0x4b0c3a < _0x37a7c1[-0x476 * 0x3 + -0x112b + 0x2 * 0xf47]; ++_0x4b0c3a ) { var _0x49abb4 = _0x467cb0(_0x41676a, _0x50f001) ; (_0x13d988 += String[_0x2145df(0x1e2)](_0x55d729 ^ _0x49abb4[0x18f1 * -0x1 + -0x17e5 * 0x1 + -0x30d7 * -0x1])), (_0x50f001 += (0x2dd * -0xd + -0x8 * 0x227 + 0x3673) * _0x49abb4[-0xd9 + 0x1702 + -0x763 * 0x3]) } _0x408609['push'](_0x13d988) } return ( (_0x3f9548['p'] = null), (function _0x970e7(_0x3e87c6, _0x536685, _0xecd4ef, _0x5acf67, _0x560641) { var _0x261736 = _0x2145df, _0x1fc1ed, _0x281ec0, _0x5c0f33, _0xd55c82, _0x37b70b, _0x12cd72 = -(0x1bdd + -0x8 * 0x116 + -0x3 * 0x664), _0x27fcf3 = [], _0x42ef1a = [-0x5 * -0x2b6 + 0x1d6c + -0x2afa, null], _0x428c87 = null, _0x4444cf = [_0x536685] for ( _0x281ec0 = Math['min'](_0x536685[_0x261736(0x259)], _0xecd4ef), _0x5c0f33 = -0x90b + -0x1 * 0x1e2f + 0x273a; _0x5c0f33 < _0x281ec0; ++_0x5c0f33 ) _0x4444cf[_0x261736(0x36e)](_0x536685[_0x5c0f33]) _0x4444cf['p'] = _0x5acf67 for (var _0x4b7ccd = []; ;) try { var _0x5cd5b9 = _0x26f45f[_0x3e87c6++] if (_0x5cd5b9 < -0x788 + 0x18c7 + 0x1 * -0x1118) { if (_0x5cd5b9 < 0x208d + -0x1031 + -0x1049 * 0x1) { if (_0x5cd5b9 < 0x1a1c + -0xbff * 0x3 + 0x27a * 0x4) _0x5cd5b9 < 0x3ee + 0x1 * 0x21c3 + -0x2e6 * 0xd ? (_0x27fcf3[++_0x12cd72] = _0x5cd5b9 < -0x61 * 0x61 + 0x1115 + 0x13ad || (-0x1d * -0x4f + 0x11c9 + 0x3 * -0x8e9 !== _0x5cd5b9 && null)) : _0x5cd5b9 < -0x783 + 0xa0d + -0x285 ? -0xb * 0x24f + 0x141a + 0x54e === _0x5cd5b9 ? ((_0x1fc1ed = _0x26f45f[_0x3e87c6++]), (_0x27fcf3[++_0x12cd72] = (_0x1fc1ed << (0x12b * 0x1f + 0x5 * 0x70c + -0x4759)) >> (-0x352 + 0x7 * 0x58f + -0x237f))) : ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0xb02 + 0x2af + -0xda9)) + _0x26f45f[_0x3e87c6 + (0x220e + 0x1 * -0x1175 + -0x1098)]), (_0x3e87c6 += -0x325 * 0x3 + 0xafe + -0x18d), (_0x27fcf3[++_0x12cd72] = (_0x1fc1ed << (-0xe7c * -0x1 + -0xe17 * -0x2 + -0x2a9a)) >> (-0x23ae * 0x1 + -0x1f8f + -0x434d * -0x1))) : -0xa * 0x15c + 0x24bc + -0x1 * 0x171f === _0x5cd5b9 ? ((_0x1fc1ed = ((_0x1fc1ed = ((_0x1fc1ed = _0x26f45f[_0x3e87c6++]) << (-0x1f87 + -0xda8 + 0x2d37)) + _0x26f45f[_0x3e87c6++]) << (-0x1d32 + -0x2 * 0x124 + 0x1f82)) + _0x26f45f[_0x3e87c6++]), (_0x27fcf3[++_0x12cd72] = (_0x1fc1ed << (0xc * -0x8 + -0x25f7 + 0x265f)) + _0x26f45f[_0x3e87c6++])) : ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x1bf7 + 0x4e9 * 0x7 + -0xc76 * 0x5)) + _0x26f45f[_0x3e87c6 + (0xba7 + -0x1611 + 0xa6b)]), (_0x3e87c6 += 0xa1e + -0x1a21 + 0x557 * 0x3), (_0x27fcf3[++_0x12cd72] = +_0x408609[_0x1fc1ed])) else { if (_0x5cd5b9 < 0x369 * -0x9 + 0x20de + -0x220) _0x5cd5b9 < -0x2626 + 0x336 * -0x5 + 0x363f ? 0x12b * -0x15 + -0x2 * -0x11f5 + 0x5ae * -0x2 === _0x5cd5b9 ? ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x8 * 0x2 + 0x35 * 0x18 + -0x500)) + _0x26f45f[_0x3e87c6 + (-0x330 + -0xec * -0x5 + -0x16b)]), (_0x3e87c6 += 0x224 + -0x19 * -0xb3 + -0x1 * 0x139d), (_0x27fcf3[++_0x12cd72] = _0x408609[_0x1fc1ed])) : (_0x27fcf3[++_0x12cd72] = void (0x5 * 0x1ef + 0x2493 * -0x1 + -0x35d * -0x8)) : 0x1abb + 0x191 * 0xd + -0x3 * 0xfaf === _0x5cd5b9 ? (_0x27fcf3[++_0x12cd72] = _0x560641) : ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (-0x20b0 + -0x3da + 0x2492)) + _0x26f45f[_0x3e87c6 + (-0x129d * 0x1 + 0x1 * -0x2316 + 0x35b4)]), (_0x3e87c6 += -0xcb8 + 0x1bb * -0xa + -0x2 * -0xf04), (_0x12cd72 = _0x12cd72 - _0x1fc1ed + (0xb3 * 0x1 + -0x2018 * 0x1 + 0x1 * 0x1f66)), (_0x281ec0 = _0x27fcf3[_0x261736(0x2a5)](_0x12cd72, _0x12cd72 + _0x1fc1ed)), (_0x27fcf3[_0x12cd72] = _0x281ec0)) else { if (_0x5cd5b9 < 0x2 * -0xf38 + 0xdd0 + 0x10b1) -0x15d2 + 0x26f0 + 0x11 * -0x101 === _0x5cd5b9 ? (_0x27fcf3[++_0x12cd72] = {}) : ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (-0x9ac + 0x1201 * 0x1 + -0x84d)) + _0x26f45f[_0x3e87c6 + (0x1ecb + -0x1bdd + 0x7 * -0x6b)]), (_0x3e87c6 += 0x6a4 + -0x922 + 0x280), (_0x281ec0 = _0x408609[_0x1fc1ed]), (_0x5c0f33 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72][_0x281ec0] = _0x5c0f33)) else { if (0x17 * -0xc3 + 0x1da5 + 0x3 * -0x405 === _0x5cd5b9) { for ( _0x281ec0 = _0x26f45f[_0x3e87c6++], _0x5c0f33 = _0x26f45f[_0x3e87c6++], _0xd55c82 = _0x4444cf; _0x281ec0 > -0x3 * 0x4ba + -0x12 * 0xb1 + 0x1aa0; --_0x281ec0 ) _0xd55c82 = _0xd55c82['p'] _0x27fcf3[++_0x12cd72] = _0xd55c82[_0x5c0f33] } else (_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x15c3 + -0x453 + -0x1168)) + _0x26f45f[_0x3e87c6 + (-0x1f3f * 0x1 + 0x1f6a + 0x6 * -0x7)]), (_0x3e87c6 += 0x1 * -0x1f4e + -0x118f * 0x1 + 0x30df), (_0x281ec0 = _0x408609[_0x1fc1ed]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72][_0x281ec0]) } } } } else { if (_0x5cd5b9 < -0xf5c + -0x6d7 + 0x164e) { if (_0x5cd5b9 < 0xc8 * -0x2f + 0xee * -0x9 + -0xf * -0x303) { if (_0x5cd5b9 < 0x1 * -0x2426 + 0x224e + 0x11 * 0x1d) { if (-0xb15 + 0x2d5 * 0x1 + -0x853 * -0x1 === _0x5cd5b9) (_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72][_0x281ec0]) else { for ( _0x281ec0 = _0x26f45f[_0x3e87c6++], _0x5c0f33 = _0x26f45f[_0x3e87c6++], _0xd55c82 = _0x4444cf; _0x281ec0 > 0x2 * -0x11b8 + 0x240a + -0x9a; --_0x281ec0 ) _0xd55c82 = _0xd55c82['p'] _0xd55c82[_0x5c0f33] = _0x27fcf3[_0x12cd72--] } } else 0x1 * 0x17f1 + 0x115 * -0x9 + 0x2d3 * -0x5 === _0x5cd5b9 ? ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x16ff + 0x158a + -0x2c81 * 0x1)) + _0x26f45f[_0x3e87c6 + (0x88f * -0x3 + 0x1c82 + 0x16a * -0x2)]), (_0x3e87c6 += 0x1 * -0xa7 + 0x18d4 + 0x1 * -0x182b), (_0x281ec0 = _0x408609[_0x1fc1ed]), (_0x5c0f33 = _0x27fcf3[_0x12cd72--]), (_0xd55c82 = _0x27fcf3[_0x12cd72--]), (_0x5c0f33[_0x281ec0] = _0xd55c82)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x5c0f33 = _0x27fcf3[_0x12cd72--]), (_0xd55c82 = _0x27fcf3[_0x12cd72--]), (_0x5c0f33[_0x281ec0] = _0xd55c82)) } else { if (_0x5cd5b9 < -0x19f3 + 0x1c6b + -0x25f) { if (0x1b * -0xbd + -0x84a * -0x2 + -0x126 * -0x3 === _0x5cd5b9) { for ( _0x281ec0 = _0x26f45f[_0x3e87c6++], _0x5c0f33 = _0x26f45f[_0x3e87c6++], _0xd55c82 = _0x4444cf, _0xd55c82 = _0x4444cf; _0x281ec0 > 0x3 * -0x65a + 0xe28 + 0x4e6; --_0x281ec0 ) _0xd55c82 = _0xd55c82['p'] ; (_0x27fcf3[++_0x12cd72] = _0xd55c82), (_0x27fcf3[++_0x12cd72] = _0x5c0f33) } else (_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] += _0x281ec0) } else 0x44b * -0x9 + 0x61 * -0xa + -0x2a86 * -0x1 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] -= _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] *= _0x281ec0)) } } else _0x5cd5b9 < 0x3 * -0x7ce + 0x907 * -0x1 + -0x1 * -0x2094 ? _0x5cd5b9 < 0xa68 + -0xc5f + 0x214 ? 0x3e * -0x7d + 0x13d1 + 0xa90 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] /= _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] %= _0x281ec0)) : -0x171d * -0x1 + -0x6a2 * -0x3 + -0x2ae6 === _0x5cd5b9 ? (_0x27fcf3[_0x12cd72] = -_0x27fcf3[_0x12cd72]) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x5c0f33 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[++_0x12cd72] = _0x5c0f33[_0x281ec0]++)) : _0x5cd5b9 < 0x2565 + -0x2 * -0xd76 + -0x1bc * 0x25 ? 0x951 + 0x13da + -0x1d08 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] == _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] != _0x281ec0)) : -0x144c * -0x1 + 0xd01 + -0x2128 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] === _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] !== _0x281ec0)) } } else { if (_0x5cd5b9 < -0x3bb + 0xdb6 + -0x9c2 * 0x1) _0x5cd5b9 < -0xe16 + -0x2 * -0x409 + 0x633 ? _0x5cd5b9 < 0x1 * 0xeea + -0x3 * 0x863 + 0x2b * 0x3e ? _0x5cd5b9 < -0x2f * -0x15 + 0x185 * 0x2 + -0x35e * 0x2 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] < _0x281ec0)) : -0x2152 + -0x1853 + 0x39ce === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] > _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] >= _0x281ec0)) : _0x5cd5b9 < 0x3 * -0x822 + 0xc76 + 0x1bb * 0x7 ? 0x20ae + -0x21ca + -0x6d * -0x3 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] << _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] >> _0x281ec0)) : -0x10 * 0x1a + -0x1431 + 0xa * 0x233 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] >>> _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] & _0x281ec0)) : _0x5cd5b9 < 0x1 * 0x1ca7 + 0x1ea1 * 0x1 + -0x31c * 0x13 ? _0x5cd5b9 < -0xa63 * -0x2 + -0x114d + -0x1 * 0x347 ? -0x12b5 + -0x153 * 0x4 + 0x8 * 0x306 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] | _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] ^ _0x281ec0)) : -0xab + 0x10c1 + 0x9 * -0x1c4 === _0x5cd5b9 ? (_0x27fcf3[_0x12cd72] = !_0x27fcf3[_0x12cd72]) : ((_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x9 * -0xd0 + -0x1 * -0xa04 + 0x2 * -0x156)) + _0x26f45f[_0x3e87c6 + (0xa6a + 0x113c + 0x1ba5 * -0x1)]) << (0x2 * -0x41b + -0x1bf1 + 0x7f * 0x49)) >> (-0x1bc0 + 0x232e + -0x75e)), (_0x3e87c6 += -0x62 * 0x31 + 0x26b * 0x7 + 0x1d7 * 0x1), _0x27fcf3[_0x12cd72] ? --_0x12cd72 : (_0x3e87c6 += _0x1fc1ed)) : _0x5cd5b9 < 0x8 * 0x493 + -0x6c * 0x49 + 0x1a * -0x37 ? -0x21 * 0x1 + -0x3 * -0xc19 + 0x2 * -0x11fb === _0x5cd5b9 ? ((_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (-0x2 * 0x11ff + 0x9d3 + 0x1a33)) + _0x26f45f[_0x3e87c6 + (0x1ba6 + -0x134f * -0x1 + -0x2ef4)]) << (0x10dc * -0x1 + -0x1130 + 0x221c)) >> (-0x5 * 0x685 + 0x1a23 + 0x686)), (_0x3e87c6 += 0x4 * 0xf9 + -0x21c5 + 0x1de3), _0x27fcf3[_0x12cd72] ? (_0x3e87c6 += _0x1fc1ed) : --_0x12cd72) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), ((_0x5c0f33 = _0x27fcf3[_0x12cd72--])[_0x281ec0] = _0x27fcf3[_0x12cd72])) : -0x5 * -0x65c + 0x15 * 0x17b + -0x3ead === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] in _0x281ec0)) : ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[_0x12cd72] = _0x27fcf3[_0x12cd72] instanceof _0x281ec0)) else { if (_0x5cd5b9 < 0x52 + 0x7 * 0x102 + -0x2 * 0x38f) { if (_0x5cd5b9 < -0x1887 + -0x303 + 0x1bc7) _0x5cd5b9 < 0x2132 + -0x592 * 0x2 + -0x15d3 ? -0x136b + -0x21cd + 0x3571 * 0x1 === _0x5cd5b9 ? ((_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0x5c0f33 = _0x27fcf3[_0x12cd72--]), (_0x27fcf3[++_0x12cd72] = delete _0x5c0f33[_0x281ec0])) : (_0x27fcf3[_0x12cd72] = typeof _0x27fcf3[_0x12cd72]) : 0xeed * 0x1 + -0xa1e + 0x2 * -0x24a === _0x5cd5b9 ? ((_0x1fc1ed = _0x26f45f[_0x3e87c6++]), (_0x281ec0 = _0x27fcf3[_0x12cd72--]), ((_0x5c0f33 = function _0x3b7712() { var _0x295f58 = _0x3b7712['_u'], _0x29116a = _0x3b7712['_v'] return _0x295f58( _0x29116a[0x28c * 0x4 + -0x6 * 0x1d6 + 0xd4], arguments, _0x29116a[0x1d72 * 0x1 + 0x7b * -0x1b + -0x1078], _0x29116a[0x11e6 + 0x1a1f * -0x1 + 0x83b], this ) })['_v'] = [_0x281ec0, _0x1fc1ed, _0x4444cf]), (_0x5c0f33['_u'] = _0x970e7), (_0x27fcf3[++_0x12cd72] = _0x5c0f33)) : ((_0x1fc1ed = _0x26f45f[_0x3e87c6++]), (_0x281ec0 = _0x27fcf3[_0x12cd72--]), ((_0xd55c82 = [ (_0x5c0f33 = function _0x465123() { var _0x2f6d57 = _0x465123['_u'], _0x399ae1 = _0x465123['_v'] return _0x2f6d57( _0x399ae1[-0x113b + 0xb * 0x71 + 0xc60], arguments, _0x399ae1[0xa13 + 0x24b0 + -0x9 * 0x532], _0x399ae1[0x1 * 0x463 + -0x56 * -0x49 + -0x1ce7], this ) }) ])['p'] = _0x4444cf), (_0x5c0f33['_v'] = [_0x281ec0, _0x1fc1ed, _0xd55c82]), (_0x5c0f33['_u'] = _0x970e7), (_0x27fcf3[++_0x12cd72] = _0x5c0f33)) else { if (_0x5cd5b9 < 0x62 * -0xd + 0xae3 + -0x5a9) 0x9d1 * -0x1 + 0x2425 + -0x1 * 0x1a17 === _0x5cd5b9 ? ((_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0xd1 * 0x2 + -0xe5 * 0x7 + 0x4a9)) + _0x26f45f[_0x3e87c6 + (0x33a + -0xb14 + 0x7db * 0x1)]) << (-0xb * -0xde + 0x1199 + -0x1b13)) >> (-0xa3d + 0xc * 0x2aa + -0x15ab)), (_0x3e87c6 += -0x2f * 0x3 + 0x2 * 0x9a3 + -0x12b7), ((_0x281ec0 = _0x4b7ccd[_0x4b7ccd['length'] - (0x427 + 0xa54 + -0xda * 0x11)])[ 0x5d4 + 0x14f2 + -0x4d * 0x59 ] = _0x3e87c6 + _0x1fc1ed)) : ((_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x349 * -0x2 + 0xa4 * -0x17 + 0x1556)) + _0x26f45f[_0x3e87c6 + (-0x86 * -0x2 + -0x1c9 + -0xbe * -0x1)]) << (0x14bf + -0x1aec + -0x1 * -0x63d)) >> (0x2 * 0x17b + -0x1e3c + 0x1b56)), (_0x3e87c6 += -0x1 * -0x1052 + 0x10 * -0x17e + 0x790), (_0x281ec0 = _0x4b7ccd[_0x4b7ccd['length'] - (-0x1ad2 + 0x1b9 * 0x2 + 0x39 * 0x69)]) && !_0x281ec0[-0x3 * 0xe8 + -0x5 * -0x142 + -0x1 * 0x391] ? ((_0x281ec0[0x25 * -0x7a + 0x21ec + -0x104a] = 0x7bf + -0x3 * -0xa43 + -0x2685), _0x281ec0[_0x261736(0x36e)](_0x3e87c6)) : _0x4b7ccd[_0x261736(0x36e)]([ -0x1d * 0x82 + -0x11f4 + 0x20af, 0x15ac + -0x399 * -0x9 + -0x360d, _0x3e87c6 ]), (_0x3e87c6 += _0x1fc1ed)) else { if (0x2263 * -0x1 + -0x689 + 0x292c === _0x5cd5b9) throw (_0x281ec0 = _0x27fcf3[_0x12cd72--]) if ( ((_0x5c0f33 = (_0x281ec0 = _0x4b7ccd['pop']())[0x1 * 0x6a1 + 0x1ceb + -0x238c]), (_0xd55c82 = _0x42ef1a[-0x1b8 + 0x1d25 + -0x3eb * 0x7]), 0x751 * 0x1 + -0xa4b + 0x7 * 0x6d === _0x5c0f33) ) _0x3e87c6 = _0x281ec0[0x1 * 0x8e + 0x128c + -0x1319] else { if (0x11f4 + 0x3 * 0x95 + -0x13b3 === _0x5c0f33) { if (-0x2607 + -0xdc8 + -0x1145 * -0x3 === _0xd55c82) _0x3e87c6 = _0x281ec0[-0x262 + -0x12bf * -0x2 + 0x13 * -0x1d9] else { if (0x6d * 0x2 + 0x2ff * -0x9 + 0x1a1e !== _0xd55c82) throw _0x42ef1a[0x3 * 0xced + 0x1dd7 + 0x16df * -0x3] if (!_0x428c87) return _0x42ef1a[0x21b7 + 0x20a5 * -0x1 + -0x5b * 0x3] ; (_0x3e87c6 = _0x428c87[-0x4bd + -0x3 * -0x353 + 0x53b * -0x1]), (_0x560641 = _0x428c87[0x149e + 0x1 * -0x751 + -0xd4b]), (_0x4444cf = _0x428c87[-0x2 * 0x94d + -0x7bf * -0x1 + 0x2 * 0x56f]), (_0x4b7ccd = _0x428c87[0x15c3 * 0x1 + -0x4 * 0x82e + -0x35 * -0x35]), (_0x27fcf3[++_0x12cd72] = _0x42ef1a[0x3 * 0xaf3 + -0x983 + -0x1755]), (_0x42ef1a = [-0x1c1c + -0x14c * 0x1a + 0x3dd4, null]), (_0x428c87 = _0x428c87[0x1a3 + 0x1 * -0x1e23 + 0x1c80]) } } else (_0x3e87c6 = _0x281ec0[-0x1 * -0x953 + 0x159 * 0x1 + -0xaaa]), (_0x281ec0[0x26ad * -0x1 + 0x2 * -0xe4b + 0x4343] = 0x100d + -0x19cc + 0x5 * 0x1f3), _0x4b7ccd[_0x261736(0x36e)](_0x281ec0) } } } } else { if (_0x5cd5b9 < 0x195 + -0x3b * -0x9d + -0x3 * 0xc7f) { if (_0x5cd5b9 < 0xd * -0x1 + 0x229 + -0x1d8) { if (-0x949 + 0x13f8 + -0xa6d === _0x5cd5b9) { for ( _0x281ec0 = _0x27fcf3[_0x12cd72--], _0x5c0f33 = null; (_0xd55c82 = _0x4b7ccd[_0x261736(0x267)]()); ) if ( 0x1e97 + 0x31 * -0x5e + -0xc97 === _0xd55c82[0x150 + 0x6 * 0x645 + -0x26ee] || 0xb29 * -0x3 + -0x333 * 0x3 + 0x2b17 === _0xd55c82[0x1 * -0x22c2 + -0x187b + 0x3b3d] ) { _0x5c0f33 = _0xd55c82 break } if (_0x5c0f33) (_0x42ef1a = [-0x11 * 0x14d + 0x1492 * 0x1 + 0x18c, _0x281ec0]), (_0x3e87c6 = _0x5c0f33[0xc28 * -0x3 + -0x8 * 0x4e1 + 0x4b82]), (_0x5c0f33[0x51e * 0x1 + 0x755 * -0x5 + 0x1f8b] = 0x1875 * 0x1 + 0x146 + -0x19bb), _0x4b7ccd[_0x261736(0x36e)](_0x5c0f33) else { if (!_0x428c87) return _0x281ec0 ; (_0x3e87c6 = _0x428c87[0x1 * 0x15be + -0x2639 + 0x107c]), (_0x560641 = _0x428c87[-0x1 * 0xe1e + 0x2042 + 0x2 * -0x911]), (_0x4444cf = _0x428c87[0x25fd + 0x1cfe + -0x42f8]), (_0x4b7ccd = _0x428c87[0x3 * 0xa76 + 0x17ce + -0x372c]), (_0x27fcf3[++_0x12cd72] = _0x281ec0), (_0x42ef1a = [-0x7 * 0x4a6 + -0x12d3 + -0x3 * -0x111f, null]), (_0x428c87 = _0x428c87[-0x29 * 0x1e + 0x9d * -0x2f + 0x21a1]) } } else (_0x12cd72 -= _0x1fc1ed = _0x26f45f[_0x3e87c6++]), (_0x5c0f33 = _0x27fcf3['slice']( _0x12cd72 + (0xf4f * -0x1 + 0x1af9 * 0x1 + -0xba9), _0x12cd72 + _0x1fc1ed + (0x230 + 0x1e17 * -0x1 + 0x6fa * 0x4) )), (_0x281ec0 = _0x27fcf3[_0x12cd72--]), (_0xd55c82 = _0x27fcf3[_0x12cd72--]), _0x281ec0['_u'] === _0x970e7 ? ((_0x281ec0 = _0x281ec0['_v']), (_0x428c87 = [_0x428c87, _0x3e87c6, _0x560641, _0x4444cf, _0x4b7ccd]), (_0x3e87c6 = _0x281ec0[0x190c + 0x3 * 0x89b + 0x32dd * -0x1]), null == _0xd55c82 && (_0xd55c82 = (function () { return this })()), (_0x560641 = _0xd55c82), ((_0x4444cf = [_0x5c0f33]['concat'](_0x5c0f33))[_0x261736(0x259)] = Math[_0x261736(0x20c)](_0x281ec0[-0x1 * 0x170b + -0x936 + 0x1 * 0x2042], _0x1fc1ed) + (0x3 * -0x4fa + 0x21ed + -0x12fe)), (_0x4444cf['p'] = _0x281ec0[-0x16 * -0x1af + 0x35f * 0x1 + 0x2867 * -0x1]), (_0x4b7ccd = [])) : (_0x27fcf3[++_0x12cd72] = _0x281ec0[_0x261736(0x207)](_0xd55c82, _0x5c0f33)) } else { if (0x60a + -0xf05 * -0x1 + 0x14cb * -0x1 === _0x5cd5b9) { for ( _0x1fc1ed = _0x26f45f[_0x3e87c6++], _0xd55c82 = [void (-0x1b5d + 0x22a1 + 0x26c * -0x3)], _0x37b70b = _0x1fc1ed; _0x37b70b > 0x1 * 0xd7e + -0x25f1 + 0x1873; --_0x37b70b ) _0xd55c82[_0x37b70b] = _0x27fcf3[_0x12cd72--] ; (_0x5c0f33 = _0x27fcf3[_0x12cd72--]), (_0x281ec0 = Function['bind'][_0x261736(0x207)](_0x5c0f33, _0xd55c82)), (_0x27fcf3[++_0x12cd72] = new _0x281ec0()) } else _0x3e87c6 += (_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x1f7 + 0x1 * -0x7d0 + 0x7 * 0xd7)) + _0x26f45f[_0x3e87c6 + (0x264a + 0xc3c + -0x3285)]) << (0x4 * 0x3ee + 0x45 * 0x51 + -0x15 * 0x1c9)) >> (0x5 * 0x199 + -0x24f * -0x2 + -0xc8b)) + (-0x1f3 * 0x6 + 0x24f7 + -0x1943) } } else _0x5cd5b9 < -0x45d * -0x2 + -0x1e51 + 0x15e0 ? 0x125b + 0x198a + -0x2b9e === _0x5cd5b9 ? ((_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (-0x269 * -0xe + 0x1 * -0x225 + -0x1f91)) + _0x26f45f[_0x3e87c6 + (-0x23bd * -0x1 + 0x1ce2 + 0x12 * -0x397)]) << (0xc61 + -0x133b + 0x6ea)) >> (0x10dc + -0x30a * 0x1 + -0xdc2)), (_0x3e87c6 += -0xc5 * -0x9 + -0x252f + 0x1e44), (_0x281ec0 = _0x27fcf3[_0x12cd72--]) || (_0x3e87c6 += _0x1fc1ed)) : ((_0x1fc1ed = ((_0x1fc1ed = (_0x26f45f[_0x3e87c6] << (0x55 * 0x14 + 0x1 * 0x1e18 + -0x3 * 0xc3c)) + _0x26f45f[_0x3e87c6 + (-0x22a3 + -0x5bf * -0x2 + 0x1726)]) << (-0x98e * 0x4 + 0x8a1 * 0x1 + 0x1da7)) >> (-0x72 * -0x26 + 0x2b * -0x51 + -0x341)), (_0x3e87c6 += 0x47 * 0x1d + 0x137 * -0x1d + 0x1b32), (_0x281ec0 = _0x27fcf3[_0x12cd72--]), _0x27fcf3[_0x12cd72] === _0x281ec0 && (--_0x12cd72, (_0x3e87c6 += _0x1fc1ed))) : -0xb * 0x33d + 0x23 * -0xf2 + 0x44fe === _0x5cd5b9 ? --_0x12cd72 : ((_0x281ec0 = _0x27fcf3[_0x12cd72]), (_0x27fcf3[++_0x12cd72] = _0x281ec0)) } } } } catch (_0x111ea4) { for ( _0x42ef1a = [-0x392 * -0x4 + 0x1a0 + -0xfe8, null]; (_0x1fc1ed = _0x4b7ccd[_0x261736(0x267)]()) && !_0x1fc1ed[0x126a + -0x1 * 0x227c + 0x1012 * 0x1]; ); if (!_0x1fc1ed) { _0x489bfb: for (; _0x428c87;) { for (_0x281ec0 = _0x428c87[0x10da * -0x1 + -0x539 + 0x1617 * 0x1]; (_0x1fc1ed = _0x281ec0[_0x261736(0x267)]());) if (_0x1fc1ed[0xaf4 * -0x2 + -0x2 * 0x132d + -0x2 * -0x1e21]) break _0x489bfb _0x428c87 = _0x428c87[0x1381 + 0x193e + -0x4f * 0x91] } if (!_0x428c87) throw _0x111ea4 ; (_0x3e87c6 = _0x428c87[0xb * -0x277 + 0x14ac + -0x226 * -0x3]), (_0x560641 = _0x428c87[0x153e + 0x1fd * -0xf + 0x897]), (_0x4444cf = _0x428c87[-0x1 * -0xa2e + 0xcd6 + 0x3 * -0x7ab]), (_0x4b7ccd = _0x428c87[-0x2 * 0x1145 + 0x2 * 0x293 + -0x3ad * -0x8]), (_0x428c87 = _0x428c87[-0x8e7 + 0x247f + -0x1b98]) } ; -0xe * 0x277 + -0x3db + -0x665 * -0x6 === (_0x281ec0 = _0x1fc1ed[-0xe65 + 0x11d1 + -0x36c]) ? ((_0x3e87c6 = _0x1fc1ed[-0x7 * -0x1c + 0x2fe * 0xa + -0x1eae]), (_0x1fc1ed[0x3f5 * 0x1 + 0x9e4 + 0x1 * -0xdd9] = -0x1622 * -0x1 + -0x1 * -0x1736 + -0x2d58), _0x4b7ccd['push'](_0x1fc1ed), (_0x27fcf3[++_0x12cd72] = _0x111ea4)) : 0x1a52 + -0xfc4 + 0x2d * -0x3c === _0x281ec0 ? ((_0x3e87c6 = _0x1fc1ed[-0x19 * 0xfe + 0x1f98 + -0x6c8]), (_0x1fc1ed[0x5 * -0x33f + 0x11d * -0x1 + 0x1158] = 0x3ac * 0x1 + 0x2 * -0x1300 + 0x152 * 0x1a), _0x4b7ccd['push'](_0x1fc1ed), (_0x42ef1a = [0x8f * 0x1d + -0x1c4b + 0xc1b, _0x111ea4])) : ((_0x3e87c6 = _0x1fc1ed[0x31f * -0x5 + -0xae7 + -0x1 * -0x1a85]), (_0x1fc1ed[0x27 * -0xb3 + -0x186 * 0xa + 0x2a81] = 0xf9 + 0x164a + -0x1741), _0x4b7ccd[_0x261736(0x36e)](_0x1fc1ed), (_0x27fcf3[++_0x12cd72] = _0x111ea4)) } })(_0x537efa, [], -0x1e + 0x2631 + -0x2613, _0x3f9548, _0x39b0b8) ) } !(function (_0xe67213, _0x19937e) { _0x19937e((window.byted_acrawler = {})) // var _0x40472c = w_0x25f3; // 'object' == typeof exports && _0x40472c(0x384) != typeof module ? _0x19937e(exports) : _0x40472c(0x1ee) == typeof define && define['amd'] ? define([_0x40472c(0x1b8)], _0x19937e) : _0x19937e((_0xe67213 = _0x40472c(0x384) != typeof globalThis ? globalThis : _0xe67213 || self)[_0x40472c(0x1f5)] = {}); })(this, function (_0x1d18f2) { 'use strict' var _0x5612de = w_0x25f3 function _0x137ba2(_0x383b51) { var _0x382940 = w_0x25f3, _0x2e23ce, _0x2c2004 function _0x3a4f3f(_0x5a726e, _0x520718) { var _0x480686 = w_0x25f3 try { var _0x4a8345 = _0x383b51[_0x5a726e](_0x520718), _0x8d9d0a = _0x4a8345[_0x480686(0x2e4)], _0x32f534 = _0x8d9d0a instanceof _0x59d886 Promise[_0x480686(0x278)](_0x32f534 ? _0x8d9d0a['v'] : _0x8d9d0a)[_0x480686(0x1ed)]( function (_0x5047be) { var _0x2a7bf3 = _0x480686 if (_0x32f534) { var _0x1c15d7 = 'return' === _0x5a726e ? _0x2a7bf3(0x2fd) : _0x2a7bf3(0x389) if (!_0x8d9d0a['k'] || _0x5047be['done']) return _0x3a4f3f(_0x1c15d7, _0x5047be) _0x5047be = _0x383b51[_0x1c15d7](_0x5047be)[_0x2a7bf3(0x2e4)] } _0x396815(_0x4a8345[_0x2a7bf3(0x1e3)] ? _0x2a7bf3(0x2fd) : _0x2a7bf3(0x2f1), _0x5047be) }, function (_0x55c002) { var _0x11b83e = _0x480686 _0x3a4f3f(_0x11b83e(0x250), _0x55c002) } ) } catch (_0x5e07d1) { _0x396815(_0x480686(0x250), _0x5e07d1) } } function _0x396815(_0x189a93, _0x2988d2) { var _0x557617 = w_0x25f3 switch (_0x189a93) { case _0x557617(0x2fd): _0x2e23ce[_0x557617(0x278)]({ value: _0x2988d2, done: !(-0x252f + 0x1b60 + 0x9cf) }) break case 'throw': _0x2e23ce[_0x557617(0x39b)](_0x2988d2) break default: _0x2e23ce[_0x557617(0x278)]({ value: _0x2988d2, done: !(-0x18ec + -0x12dc + 0x2bc9) }) } ; (_0x2e23ce = _0x2e23ce['next']) ? _0x3a4f3f(_0x2e23ce[_0x557617(0x392)], _0x2e23ce[_0x557617(0x327)]) : (_0x2c2004 = null) } ; (this['_invoke'] = function (_0xd1d2b8, _0x168b0a) { return new Promise(function (_0x1a939a, _0x9b7633) { var _0x1f7808 = w_0x25f3, _0x270c76 = { key: _0xd1d2b8, arg: _0x168b0a, resolve: _0x1a939a, reject: _0x9b7633, next: null } _0x2c2004 ? (_0x2c2004 = _0x2c2004[_0x1f7808(0x389)] = _0x270c76) : ((_0x2e23ce = _0x2c2004 = _0x270c76), _0x3a4f3f(_0xd1d2b8, _0x168b0a)) }) }), _0x382940(0x1ee) != typeof _0x383b51[_0x382940(0x2fd)] && (this[_0x382940(0x2fd)] = void (-0xe73 + -0xe * 0x24b + 0x2e8d)) } function _0x59d886(_0x53e3a8, _0x594492) { ; (this['v'] = _0x53e3a8), (this['k'] = _0x594492) } function _0x1d9867(_0x38463f, _0x559d1b, _0x1b2c54, _0x595501) { return { getMetadata: function (_0x397823) { var _0x2d4b6b = w_0x25f3 _0x1fca4f(_0x595501, _0x2d4b6b(0x349)), _0x525dc3(_0x397823) var _0x18296f = _0x38463f[_0x397823] if (void (-0x15d1 + 0x4d8 + -0xb * -0x18b) !== _0x18296f) { if (-0x1fa5 * -0x1 + 0x6b8 + -0x265c === _0x559d1b) { var _0x192f00 = _0x18296f[_0x2d4b6b(0x1d4)] if (void (-0x1 * 0x46d + -0x74 * 0x6 + 0x1f * 0x3b) !== _0x192f00) return _0x192f00[_0x1b2c54] } else { if (0x409 * 0x8 + 0x53 * -0x3e + -0xc2c === _0x559d1b) { var _0x6d3fe1 = _0x18296f[_0x2d4b6b(0x261)] if (void (0x1c7c + 0x8b0 + -0x7a * 0x4e) !== _0x6d3fe1) return _0x6d3fe1[_0x2d4b6b(0x32b)](_0x1b2c54) } else { if (Object[_0x2d4b6b(0x3b8)][_0x2d4b6b(0x334)](_0x18296f, _0x2d4b6b(0x2ac))) return _0x18296f[_0x2d4b6b(0x2ac)] } } } }, setMetadata: function (_0x3ee519, _0x4e53ba) { var _0x22e2d1 = w_0x25f3 _0x1fca4f(_0x595501, _0x22e2d1(0x395)), _0x525dc3(_0x3ee519) var _0x39b490 = _0x38463f[_0x3ee519] if ( (void (0x181 * -0x1 + 0x102 * 0x9 + -0x791) === _0x39b490 && (_0x39b490 = _0x38463f[_0x3ee519] = {}), -0x97e + -0x39 * -0x22 + 0x11 * 0x1d === _0x559d1b) ) { var _0x38c721 = _0x39b490[_0x22e2d1(0x1d4)] void (-0x2f9 * -0x7 + 0x8fe + -0x1dcd * 0x1) === _0x38c721 && (_0x38c721 = _0x39b490[_0x22e2d1(0x1d4)] = {}), (_0x38c721[_0x1b2c54] = _0x4e53ba) } else { if (-0x4dc + 0xbb0 + -0x6d2 === _0x559d1b) { var _0x4ca087 = _0x39b490['priv'] void (0x29 * 0xb9 + -0x24a + -0x1b57) === _0x4ca087 && (_0x4ca087 = _0x39b490[_0x22e2d1(0x261)] = new Map()), _0x4ca087[_0x22e2d1(0x1e4)](_0x1b2c54, _0x4e53ba) } else _0x39b490[_0x22e2d1(0x2ac)] = _0x4e53ba } } } } function _0x43bce4(_0x282431, _0x336297) { var _0xd4a703 = w_0x25f3, _0x2b5c4b = _0x282431[Symbol['metadata'] || Symbol[_0xd4a703(0x31e)]('Symbol.metadata')], _0x191a7e = Object[_0xd4a703(0x388)](_0x336297) if (-0x22cd + -0x378 + -0x65 * -0x61 !== _0x191a7e[_0xd4a703(0x259)]) { for (var _0x434093 = 0x1d66 + -0x2 * 0xa03 + -0x960; _0x434093 < _0x191a7e[_0xd4a703(0x259)]; _0x434093++) { var _0x720e9a = _0x191a7e[_0x434093], _0x14e145 = _0x336297[_0x720e9a], _0x2965bc = _0x2b5c4b ? _0x2b5c4b[_0x720e9a] : null, _0x530b43 = _0x14e145[_0xd4a703(0x1d4)], _0x36f2c2 = _0x2965bc ? _0x2965bc[_0xd4a703(0x1d4)] : null _0x530b43 && _0x36f2c2 && Object['setPrototypeOf'](_0x530b43, _0x36f2c2) var _0x1732ba = _0x14e145[_0xd4a703(0x261)] if (_0x1732ba) { var _0x550c9f = Array[_0xd4a703(0x29c)](_0x1732ba['values']()), _0x5cb426 = _0x2965bc ? _0x2965bc[_0xd4a703(0x261)] : null _0x5cb426 && (_0x550c9f = _0x550c9f[_0xd4a703(0x2b8)](_0x5cb426)), (_0x14e145[_0xd4a703(0x261)] = _0x550c9f) } _0x2965bc && Object[_0xd4a703(0x23b)](_0x14e145, _0x2965bc) } _0x2b5c4b && Object['setPrototypeOf'](_0x336297, _0x2b5c4b), (_0x282431[Symbol[_0xd4a703(0x3a3)] || Symbol['for']('Symbol.metadata')] = _0x336297) } } function _0x26f5a8(_0x4a45da, _0x3cff50) { return function (_0x346098) { var _0x33211b = w_0x25f3 _0x1fca4f(_0x3cff50, 'addInitializer'), _0x3ccc16(_0x346098, _0x33211b(0x3ba)), _0x4a45da[_0x33211b(0x36e)](_0x346098) } } function _0x2bb58f(_0x256829, _0x48125d, _0x3ef27c, _0x2a2bd4, _0x3688dc, _0x348e43, _0x559d92, _0x5a7ba4, _0x9da1fe) { var _0x2a79c7 = w_0x25f3, _0x2e3577 switch (_0x348e43) { case 0xf31 + -0x3 * 0x2dd + -0x699: _0x2e3577 = _0x2a79c7(0x1b9) break case 0x269d + -0x1291 + -0x140a: _0x2e3577 = _0x2a79c7(0x25a) break case 0x24f * -0x9 + 0x12b3 + 0x217: _0x2e3577 = _0x2a79c7(0x181) break case 0xee9 + -0xe3b * 0x1 + -0xaa: _0x2e3577 = _0x2a79c7(0x35d) break default: _0x2e3577 = _0x2a79c7(0x23c) } var _0x12a0c0, _0x433c00, _0x37f6a8 = { kind: _0x2e3577, name: _0x5a7ba4 ? '#' + _0x48125d : _0x48125d, isStatic: _0x559d92, isPrivate: _0x5a7ba4 }, _0x71731a = { v: !(-0x1b16 * -0x1 + 0x1 * 0x1fe1 + -0x2 * 0x1d7b) } if ((0x15e0 + -0xdfe + -0x7e2 !== _0x348e43 && (_0x37f6a8['addInitializer'] = _0x26f5a8(_0x3688dc, _0x71731a)), _0x5a7ba4)) { ; (_0x12a0c0 = -0x2 * 0xd69 + 0x2a1 * 0x1 + 0x1833), (_0x433c00 = Symbol(_0x48125d)) var _0x18857b = {} 0x2b + 0x9ef * 0x1 + -0x1 * 0xa1a === _0x348e43 ? ((_0x18857b[_0x2a79c7(0x32b)] = _0x3ef27c[_0x2a79c7(0x32b)]), (_0x18857b['set'] = _0x3ef27c['set'])) : -0x2 * 0xd06 + 0x1816 + 0x1f8 === _0x348e43 ? (_0x18857b[_0x2a79c7(0x32b)] = function () { var _0x14604b = _0x2a79c7 return _0x3ef27c[_0x14604b(0x2e4)] }) : ((0x6bc + 0x1 * 0x2095 + 0x10 * -0x275 !== _0x348e43 && -0x1207 + 0x31f + 0x13 * 0xc9 !== _0x348e43) || (_0x18857b[_0x2a79c7(0x32b)] = function () { var _0x290422 = _0x2a79c7 return _0x3ef27c[_0x290422(0x32b)][_0x290422(0x334)](this) }), (0x1296 + -0x1481 + 0x1ec !== _0x348e43 && -0x1892 + -0xfa7 + 0x283d * 0x1 !== _0x348e43) || (_0x18857b[_0x2a79c7(0x1e4)] = function (_0x4e18b8) { var _0x7e7883 = _0x2a79c7 _0x3ef27c['set'][_0x7e7883(0x334)](this, _0x4e18b8) })), (_0x37f6a8[_0x2a79c7(0x1d0)] = _0x18857b) } else (_0x12a0c0 = 0xca0 * 0x1 + 0x83 + -0x52 * 0x29), (_0x433c00 = _0x48125d) try { return _0x256829(_0x9da1fe, Object[_0x2a79c7(0x2a0)](_0x37f6a8, _0x1d9867(_0x2a2bd4, _0x12a0c0, _0x433c00, _0x71731a))) } finally { _0x71731a['v'] = !(0x6ad + -0x17a9 + 0x10fc) } } function _0x1fca4f(_0x322983, _0x544667) { var _0x43acb9 = w_0x25f3 if (_0x322983['v']) throw new Error(_0x43acb9(0x214) + _0x544667 + _0x43acb9(0x168)) } function _0x525dc3(_0x3ef577) { var _0x42d9e9 = w_0x25f3 if (_0x42d9e9(0x2ed) != typeof _0x3ef577) throw new TypeError(_0x42d9e9(0x2e7) + _0x3ef577) } function _0x3ccc16(_0x56cd04, _0x56ab29) { var _0x12ff08 = w_0x25f3 if ('function' != typeof _0x56cd04) throw new TypeError(_0x56ab29 + _0x12ff08(0x2f8)) } function _0x32dfd4(_0x43869e, _0x434307) { var _0x3fc8b9 = w_0x25f3, _0xd7b002 = typeof _0x434307 if (-0x1116 + 0x183f + 0x2 * -0x394 === _0x43869e) { if (_0x3fc8b9(0x17d) !== _0xd7b002 || null === _0x434307) throw new TypeError(_0x3fc8b9(0x1fd)) void (-0x39e * -0x9 + -0x1 * 0x1241 + -0x7 * 0x20b) !== _0x434307[_0x3fc8b9(0x32b)] && _0x3ccc16(_0x434307[_0x3fc8b9(0x32b)], _0x3fc8b9(0x170)), void (0xeff * 0x1 + 0x2673 + 0x1 * -0x3572) !== _0x434307[_0x3fc8b9(0x1e4)] && _0x3ccc16(_0x434307[_0x3fc8b9(0x1e4)], _0x3fc8b9(0x231)), void (-0x1558 + -0x1b41 * 0x1 + 0x57 * 0x8f) !== _0x434307['init'] && _0x3ccc16(_0x434307['init'], _0x3fc8b9(0x22f)), void (-0x148f + 0xfa3 * 0x1 + 0x4ec) !== _0x434307[_0x3fc8b9(0x2d0)] && _0x3ccc16(_0x434307[_0x3fc8b9(0x2d0)], 'accessor.initializer') } else { if (_0x3fc8b9(0x1ee) !== _0xd7b002) throw new TypeError( (0xf1a + 0xce * 0x1f + -0x280c === _0x43869e ? _0x3fc8b9(0x23c) : 0x2428 + -0x6 * -0x635 + -0x495c === _0x43869e ? _0x3fc8b9(0x19c) : _0x3fc8b9(0x25a)) + _0x3fc8b9(0x2cd) ) } } function _0x372120(_0x40b476) { var _0x3e830c = w_0x25f3, _0x49c5be return ( null == (_0x49c5be = _0x40b476['init']) && (_0x49c5be = _0x40b476[_0x3e830c(0x2d0)]) && _0x3e830c(0x384) != typeof console && console[_0x3e830c(0x3b0)](_0x3e830c(0x30b)), _0x49c5be ) } function _0x481bfe(_0x40006c, _0xdbd444, _0x2c21df, _0x2a4c98, _0x438b52, _0x13e34d, _0x5ae545, _0xa813f0, _0x4c4bfe) { var _0x2ee2fe = w_0x25f3, _0x2f4463, _0x470ce0, _0x5e0119, _0x2b261c, _0x52c40b, _0x4e02cf, _0x1fa0af = _0x2c21df[-0x987 + 0x27 * -0xdf + -0x40 * -0xae] if ( (_0x5ae545 ? (_0x2f4463 = -0xa89 * 0x1 + -0xd71 + 0x17fa === _0x438b52 || -0x272 * -0xd + -0x1c * 0xb2 + -0xc51 === _0x438b52 ? { get: _0x2c21df[0xefd + 0x232b + -0x3225], set: _0x2c21df[0x21b5 * -0x1 + -0x1015 + 0x31ce] } : 0x17ef + -0x1d3 + 0x1619 * -0x1 === _0x438b52 ? { get: _0x2c21df[-0x1e92 + 0xff * -0xe + 0x2c87] } : -0x2211 + 0x1568 + 0xcad === _0x438b52 ? { set: _0x2c21df[-0xcd2 + 0x126e + 0x1 * -0x599] } : { value: _0x2c21df[0x2293 + -0x1815 + -0xa7b * 0x1] }) : 0x23f1 + -0x93b * -0x4 + 0x1 * -0x48dd !== _0x438b52 && (_0x2f4463 = Object[_0x2ee2fe(0x2a6)](_0xdbd444, _0x2a4c98)), -0x9a5 + 0x2cc * -0x5 + -0xb * -0x226 === _0x438b52 ? (_0x5e0119 = { get: _0x2f4463['get'], set: _0x2f4463[_0x2ee2fe(0x1e4)] }) : -0xb5c + 0x210d + -0x1ab * 0xd === _0x438b52 ? (_0x5e0119 = _0x2f4463[_0x2ee2fe(0x2e4)]) : -0x12e2 * -0x2 + 0x1 * 0x815 + -0x2dd6 === _0x438b52 ? (_0x5e0119 = _0x2f4463['get']) : 0x6 * 0x182 + 0x15fd + -0x1f05 * 0x1 === _0x438b52 && (_0x5e0119 = _0x2f4463[_0x2ee2fe(0x1e4)]), _0x2ee2fe(0x1ee) == typeof _0x1fa0af) ) void (0x12b3 * -0x2 + 0x1229 * 0x1 + 0x133d) !== (_0x2b261c = _0x2bb58f(_0x1fa0af, _0x2a4c98, _0x2f4463, _0xa813f0, _0x4c4bfe, _0x438b52, _0x13e34d, _0x5ae545, _0x5e0119)) && (_0x32dfd4(_0x438b52, _0x2b261c), -0x655 + -0xb75 + 0x9 * 0x1fa === _0x438b52 ? (_0x470ce0 = _0x2b261c) : 0x2239 + -0x9 * -0x42b + -0x47bb === _0x438b52 ? ((_0x470ce0 = _0x372120(_0x2b261c)), (_0x52c40b = _0x2b261c[_0x2ee2fe(0x32b)] || _0x5e0119[_0x2ee2fe(0x32b)]), (_0x4e02cf = _0x2b261c['set'] || _0x5e0119['set']), (_0x5e0119 = { get: _0x52c40b, set: _0x4e02cf })) : (_0x5e0119 = _0x2b261c)) else for ( var _0x5801c7 = _0x1fa0af['length'] - (0x2435 + 0x18d0 + 0x16 * -0x2c6); _0x5801c7 >= 0x3ab + 0x58e * -0x6 + 0x1da9; _0x5801c7-- ) { var _0x2c9ee5 void (0x11 * -0x22 + -0x29 * -0x45 + 0x8cb * -0x1) !== (_0x2b261c = _0x2bb58f( _0x1fa0af[_0x5801c7], _0x2a4c98, _0x2f4463, _0xa813f0, _0x4c4bfe, _0x438b52, _0x13e34d, _0x5ae545, _0x5e0119 )) && (_0x32dfd4(_0x438b52, _0x2b261c), -0x220e + 0x3 * 0x4d5 + 0x138f === _0x438b52 ? (_0x2c9ee5 = _0x2b261c) : -0x2 * -0x1281 + 0x48f * 0x7 + -0x44ea === _0x438b52 ? ((_0x2c9ee5 = _0x372120(_0x2b261c)), (_0x52c40b = _0x2b261c[_0x2ee2fe(0x32b)] || _0x5e0119[_0x2ee2fe(0x32b)]), (_0x4e02cf = _0x2b261c[_0x2ee2fe(0x1e4)] || _0x5e0119[_0x2ee2fe(0x1e4)]), (_0x5e0119 = { get: _0x52c40b, set: _0x4e02cf })) : (_0x5e0119 = _0x2b261c), void (0x204c + -0x2618 + 0x7 * 0xd4) !== _0x2c9ee5 && (void (0x3b3 * 0x9 + -0x2709 + 0x69 * 0xe) === _0x470ce0 ? (_0x470ce0 = _0x2c9ee5) : _0x2ee2fe(0x1ee) == typeof _0x470ce0 ? (_0x470ce0 = [_0x470ce0, _0x2c9ee5]) : _0x470ce0['push'](_0x2c9ee5))) } if (-0x236c + 0xbb8 + 0x17b4 === _0x438b52 || 0x1 * 0x13e5 + -0x73 * -0xd + -0x1 * 0x19bb === _0x438b52) { if (void (0x213e + 0xef + -0x222d) === _0x470ce0) _0x470ce0 = function (_0x2f3a47, _0x29873e) { return _0x29873e } else { if (_0x2ee2fe(0x1ee) != typeof _0x470ce0) { var _0x41d3b0 = _0x470ce0 _0x470ce0 = function (_0x434b4b, _0x5f49e4) { var _0x463980 = _0x2ee2fe for ( var _0x99d6c0 = _0x5f49e4, _0x29ba97 = -0x120f * 0x1 + 0x1241 + -0x1 * 0x32; _0x29ba97 < _0x41d3b0['length']; _0x29ba97++ ) _0x99d6c0 = _0x41d3b0[_0x29ba97][_0x463980(0x334)](_0x434b4b, _0x99d6c0) return _0x99d6c0 } } else { var _0x58c0cd = _0x470ce0 _0x470ce0 = function (_0x15ad86, _0x1885c8) { return _0x58c0cd['call'](_0x15ad86, _0x1885c8) } } } _0x40006c[_0x2ee2fe(0x36e)](_0x470ce0) } 0x1 * -0x241 + 0xf4f + -0xd0e !== _0x438b52 && (0x1 * 0x10e7 + -0x47c + -0x2 * 0x635 === _0x438b52 ? ((_0x2f4463[_0x2ee2fe(0x32b)] = _0x5e0119[_0x2ee2fe(0x32b)]), (_0x2f4463[_0x2ee2fe(0x1e4)] = _0x5e0119[_0x2ee2fe(0x1e4)])) : -0x53 * 0x6b + 0x16e * 0x8 + 0x1743 === _0x438b52 ? (_0x2f4463[_0x2ee2fe(0x2e4)] = _0x5e0119) : 0x4 * -0x4cd + -0x1 * -0x211a + 0x1 * -0xde3 === _0x438b52 ? (_0x2f4463['get'] = _0x5e0119) : -0x1d4b * 0x1 + 0x1853 + 0x4fc === _0x438b52 && (_0x2f4463[_0x2ee2fe(0x1e4)] = _0x5e0119), _0x5ae545 ? 0x5 * -0x28 + 0xcfd + -0xc34 * 0x1 === _0x438b52 ? (_0x40006c[_0x2ee2fe(0x36e)](function (_0x21a97b, _0x5eb78e) { var _0x40880e = _0x2ee2fe return _0x5e0119[_0x40880e(0x32b)][_0x40880e(0x334)](_0x21a97b, _0x5eb78e) }), _0x40006c[_0x2ee2fe(0x36e)](function (_0x2fa7d1, _0x120ab2) { var _0x14b22a = _0x2ee2fe return _0x5e0119[_0x14b22a(0x1e4)][_0x14b22a(0x334)](_0x2fa7d1, _0x120ab2) })) : -0x4 * 0x64c + -0x1 * 0xe54 + 0x13c3 * 0x2 === _0x438b52 ? _0x40006c['push'](_0x5e0119) : _0x40006c[_0x2ee2fe(0x36e)](function (_0xcb08af, _0x156de1) { var _0x327ef4 = _0x2ee2fe return _0x5e0119[_0x327ef4(0x334)](_0xcb08af, _0x156de1) }) : Object[_0x2ee2fe(0x175)](_0xdbd444, _0x2a4c98, _0x2f4463)) } function _0xa6bc9e(_0x4ceb2c, _0x1b99e7, _0xa8afec, _0x19fdc6, _0x501635) { var _0x4c0532 = w_0x25f3 for ( var _0xcd77fa, _0x29d8ee, _0x1865b0 = new Map(), _0x4b9277 = new Map(), _0xbb3086 = 0x8 * 0x5e + 0x1f79 + -0x17 * 0x17f; _0xbb3086 < _0x501635[_0x4c0532(0x259)]; _0xbb3086++ ) { var _0x58c865 = _0x501635[_0xbb3086] if (Array['isArray'](_0x58c865)) { var _0x203b06, _0x4069ae, _0x479925, _0x2ccf6e = _0x58c865[-0x3f4 + -0x1cc4 + -0x1 * -0x20b9], _0x138f67 = _0x58c865[0x17b7 + 0x1 * 0x1525 + -0x2cda], _0xf00e58 = _0x58c865[_0x4c0532(0x259)] > -0x9f5 + -0xd * -0x103 + -0x5 * 0xa3, _0x356344 = _0x2ccf6e >= -0x14cc + -0xe02 + 0x6f7 * 0x5 if ( (_0x356344 ? ((_0x203b06 = _0x1b99e7), (_0x4069ae = _0x19fdc6), 0x7 * -0x3c7 + -0x225e + 0x3ccf != (_0x2ccf6e -= -0xdf * 0x17 + -0xb0c + 0x1f1a) && (_0x479925 = _0x29d8ee = _0x29d8ee || [])) : ((_0x203b06 = _0x1b99e7[_0x4c0532(0x344)]), (_0x4069ae = _0xa8afec), -0xc0c + 0x1a8e + -0x2 * 0x741 !== _0x2ccf6e && (_0x479925 = _0xcd77fa = _0xcd77fa || [])), -0x135b + 0xba6 + -0x7b5 * -0x1 !== _0x2ccf6e && !_0xf00e58) ) { var _0x5ef9f5 = _0x356344 ? _0x4b9277 : _0x1865b0, _0x4ff161 = _0x5ef9f5[_0x4c0532(0x32b)](_0x138f67) || 0x2 * 0x27b + 0x137 * 0x1d + -0x2831 if ( !(-0xea4 + 0x2178 + 0x96a * -0x2) === _0x4ff161 || (-0x1dce + 0x245d + -0x346 * 0x2 === _0x4ff161 && -0x6 * -0x38f + -0x4 * 0x179 + 0xf72 * -0x1 !== _0x2ccf6e) || (0x1265 + -0x40 * 0x6a + -0x21 * -0x3f === _0x4ff161 && -0x14bf + -0x1fa6 + 0x3468 !== _0x2ccf6e) ) throw new Error(_0x4c0532(0x351) + _0x138f67) !_0x4ff161 && _0x2ccf6e > -0x895 * 0x1 + 0x9fa + -0x163 ? _0x5ef9f5[_0x4c0532(0x1e4)](_0x138f67, _0x2ccf6e) : _0x5ef9f5['set'](_0x138f67, !(-0x1a * 0x12 + 0xa1 * 0x1d + -0x1069 * 0x1)) } _0x481bfe(_0x4ceb2c, _0x203b06, _0x58c865, _0x138f67, _0x2ccf6e, _0x356344, _0xf00e58, _0x4069ae, _0x479925) } } _0x3657e2(_0x4ceb2c, _0xcd77fa), _0x3657e2(_0x4ceb2c, _0x29d8ee) } function _0x3657e2(_0x27f72c, _0x8206e1) { var _0x4690f1 = w_0x25f3 _0x8206e1 && _0x27f72c[_0x4690f1(0x36e)](function (_0x5a459a) { var _0x25d832 = _0x4690f1 for (var _0x3abe8d = -0x2d8 + -0x38c + 0x664; _0x3abe8d < _0x8206e1['length']; _0x3abe8d++) _0x8206e1[_0x3abe8d][_0x25d832(0x334)](_0x5a459a) return _0x5a459a }) } function _0x5f3676(_0x5c13b5, _0x4779ee, _0x3479c8, _0x3cb840) { var _0x5df6f5 = w_0x25f3 if (_0x3cb840['length'] > -0x1744 + -0xfb * 0xd + 0x2403) { for ( var _0x3c4c21 = [], _0x504436 = _0x4779ee, _0x1b5d8b = _0x4779ee['name'], _0x38689d = _0x3cb840[_0x5df6f5(0x259)] - (-0x1f5e + 0x1e2c * 0x1 + 0x133); _0x38689d >= 0x878 + -0x1269 * 0x2 + 0x1c5a; _0x38689d-- ) { var _0x2bbf37 = { v: !(0x1 * -0x17dc + -0x1f4 * -0x10 + -0x3d * 0x1f) } try { var _0x175a61 = Object['assign']( { kind: _0x5df6f5(0x19c), name: _0x1b5d8b, addInitializer: _0x26f5a8(_0x3c4c21, _0x2bbf37) }, _0x1d9867(_0x3479c8, -0x1dfa + -0x1517 + 0x3311, _0x1b5d8b, _0x2bbf37) ), _0x23fff7 = _0x3cb840[_0x38689d](_0x504436, _0x175a61) } finally { _0x2bbf37['v'] = !(0x1 * -0x1e5d + -0xba7 * 0x2 + 0x35ab) } void (-0x2bf + -0x103d * -0x1 + -0xd7e) !== _0x23fff7 && (_0x32dfd4(0xcf3 + -0x9f8 + -0x2f1, _0x23fff7), (_0x504436 = _0x23fff7)) } _0x5c13b5[_0x5df6f5(0x36e)](_0x504436, function () { var _0x52b1c0 = _0x5df6f5 for (var _0x4f0e95 = 0x18 * 0x57 + 0x9f2 * 0x3 + -0x25fe; _0x4f0e95 < _0x3c4c21[_0x52b1c0(0x259)]; _0x4f0e95++) _0x3c4c21[_0x4f0e95][_0x52b1c0(0x334)](_0x504436) }) } } function _0x51be3f(_0x44772e, _0x5243ca, _0x398fa6) { var _0x234a54 = w_0x25f3, _0x13ba59 = [], _0x3f8aa9 = {}, _0x129506 = {} return ( _0xa6bc9e(_0x13ba59, _0x44772e, _0x129506, _0x3f8aa9, _0x5243ca), _0x43bce4(_0x44772e[_0x234a54(0x344)], _0x129506), _0x5f3676(_0x13ba59, _0x44772e, _0x3f8aa9, _0x398fa6), _0x43bce4(_0x44772e, _0x3f8aa9), _0x13ba59 ) } function _0x281b3b() { function _0x556aac(_0xe6f04c, _0x2cf155) { return function (_0x4ecc37) { var _0x253daa = w_0x25f3 !(function (_0x109a83, _0x5991fe) { var _0x11a2fc = w_0x25f3 if (_0x109a83['v']) throw new Error(_0x11a2fc(0x257)) })(_0x2cf155), _0x3020d2(_0x4ecc37, _0x253daa(0x3ba)), _0xe6f04c[_0x253daa(0x36e)](_0x4ecc37) } } function _0x193050(_0xc0995a, _0x3ee2bb, _0x30e0b6, _0xba208c, _0x262641, _0x4fa001, _0x1bb0d5, _0xa6e531) { var _0x208bac = w_0x25f3, _0x59dc77 switch (_0x262641) { case 0x1af6 + -0xd13 + -0xde2: _0x59dc77 = 'accessor' break case 0xfda + -0x760 + -0x878: _0x59dc77 = _0x208bac(0x25a) break case 0x1a * 0xb9 + 0xc3f + -0x1f06: _0x59dc77 = 'getter' break case -0xb42 * 0x3 + -0x12d9 + 0x34a3: _0x59dc77 = 'setter' break default: _0x59dc77 = _0x208bac(0x23c) } var _0x1b169f, _0x3fad4b, _0x1050cb = { kind: _0x59dc77, name: _0x1bb0d5 ? '#' + _0x3ee2bb : _0x3ee2bb, static: _0x4fa001, private: _0x1bb0d5 }, _0x252772 = { v: !(0x5 * 0x4d5 + -0x1 * 0x1d6e + 0x546) } ; -0x21ff + -0x127a + -0x3479 * -0x1 !== _0x262641 && (_0x1050cb['addInitializer'] = _0x556aac(_0xba208c, _0x252772)), -0x2c9 + -0x27 + 0x2f0 === _0x262641 ? _0x1bb0d5 ? ((_0x1b169f = _0x30e0b6['get']), (_0x3fad4b = _0x30e0b6[_0x208bac(0x1e4)])) : ((_0x1b169f = function () { return this[_0x3ee2bb] }), (_0x3fad4b = function (_0x417555) { this[_0x3ee2bb] = _0x417555 })) : 0x1 * -0x1d61 + -0x1 * 0x841 + -0xc8c * -0x3 === _0x262641 ? (_0x1b169f = function () { var _0x195f9b = _0x208bac return _0x30e0b6[_0x195f9b(0x2e4)] }) : ((0x1 * -0x1e49 + 0x1 * 0x1eef + 0x37 * -0x3 !== _0x262641 && 0x1 * 0x204a + -0x137 * -0xb + -0x2da4 !== _0x262641) || (_0x1b169f = function () { var _0x3ad118 = _0x208bac return _0x30e0b6[_0x3ad118(0x32b)][_0x3ad118(0x334)](this) }), (0x729 + -0x7ae + 0x1 * 0x86 !== _0x262641 && -0xa * -0x161 + -0x512 + -0x2 * 0x45a !== _0x262641) || (_0x3fad4b = function (_0x37b522) { var _0x599416 = _0x208bac _0x30e0b6[_0x599416(0x1e4)]['call'](this, _0x37b522) })), (_0x1050cb[_0x208bac(0x1d0)] = _0x1b169f && _0x3fad4b ? { get: _0x1b169f, set: _0x3fad4b } : _0x1b169f ? { get: _0x1b169f } : { set: _0x3fad4b }) try { return _0xc0995a(_0xa6e531, _0x1050cb) } finally { _0x252772['v'] = !(-0x1 * 0x1ecf + 0x1cfc + 0x1d3) } } function _0x3020d2(_0x5684cc, _0x512b77) { var _0x3b7e7a = w_0x25f3 if (_0x3b7e7a(0x1ee) != typeof _0x5684cc) throw new TypeError(_0x512b77 + '\x20must\x20be\x20a\x20function') } function _0x13d7df(_0x22787a, _0x4a8dfe) { var _0x994eff = w_0x25f3, _0x751eff = typeof _0x4a8dfe if (-0x690 + 0x133f * -0x2 + 0x2d0f === _0x22787a) { if (_0x994eff(0x17d) !== _0x751eff || null === _0x4a8dfe) throw new TypeError(_0x994eff(0x1fd)) void (-0x2af + 0x838 + -0xd * 0x6d) !== _0x4a8dfe[_0x994eff(0x32b)] && _0x3020d2(_0x4a8dfe[_0x994eff(0x32b)], _0x994eff(0x170)), void (0x1b * -0x43 + -0x24c8 + 0x2bd9) !== _0x4a8dfe[_0x994eff(0x1e4)] && _0x3020d2(_0x4a8dfe[_0x994eff(0x1e4)], _0x994eff(0x231)), void (-0x2a4 + 0x35 * -0x1d + 0x8a5) !== _0x4a8dfe[_0x994eff(0x3b9)] && _0x3020d2(_0x4a8dfe[_0x994eff(0x3b9)], _0x994eff(0x22f)) } else { if ('function' !== _0x751eff) throw new TypeError( (-0x800 + 0xd * 0x75 + 0x20f === _0x22787a ? _0x994eff(0x23c) : 0x13ad + 0x1db0 + -0x3153 === _0x22787a ? _0x994eff(0x19c) : _0x994eff(0x25a)) + '\x20decorators\x20must\x20return\x20a\x20function\x20or\x20void\x200' ) } } function _0x3345ab(_0xc8cad8, _0x5d015f, _0x32f33f, _0x5f5169, _0x23451f, _0x2595f8, _0xb8bdee, _0x2c3fb2) { var _0x1d74f6 = w_0x25f3, _0x584e33, _0x103b18, _0x5d6523, _0x2d18a1, _0x2b9fd3, _0x11479e, _0x4ef3d6 = _0x32f33f[0x23c3 + -0x1a88 + 0x1 * -0x93b] if ( (_0xb8bdee ? (_0x584e33 = 0x7ed * 0x1 + 0xac9 + -0x12b6 === _0x23451f || 0x4 * 0x7f5 + 0x11ab + 0x712 * -0x7 === _0x23451f ? { get: _0x32f33f[0x265e * 0x1 + -0x23e1 + -0x1 * 0x27a], set: _0x32f33f[0x108e + -0x2551 + 0x1b * 0xc5] } : 0x19bc + 0x1c0d * 0x1 + 0x35c6 * -0x1 === _0x23451f ? { get: _0x32f33f[-0x7fd * 0x4 + 0x1b6c + 0x48b] } : 0x149a + 0x2522 + -0x39b8 === _0x23451f ? { set: _0x32f33f[-0x1 * 0x3ad + -0xb4e * 0x2 + -0x9 * -0x2ec] } : { value: _0x32f33f[0x21a6 + -0x7 + -0x219c] }) : 0x12ab * 0x1 + -0x1f41 + 0xc96 !== _0x23451f && (_0x584e33 = Object[_0x1d74f6(0x2a6)](_0x5d015f, _0x5f5169)), 0x11 * -0xf7 + -0x4 * 0x7be + 0x2f60 === _0x23451f ? (_0x5d6523 = { get: _0x584e33[_0x1d74f6(0x32b)], set: _0x584e33['set'] }) : 0x1e3 + 0x2 * 0x11ef + -0x25bf === _0x23451f ? (_0x5d6523 = _0x584e33[_0x1d74f6(0x2e4)]) : -0x6b + 0x1ff8 + -0xfc5 * 0x2 === _0x23451f ? (_0x5d6523 = _0x584e33['get']) : 0x2577 + -0x2272 + -0x301 === _0x23451f && (_0x5d6523 = _0x584e33[_0x1d74f6(0x1e4)]), 'function' == typeof _0x4ef3d6) ) void (0x1bdc * -0x1 + 0x2343 + -0x1 * 0x767) !== (_0x2d18a1 = _0x193050(_0x4ef3d6, _0x5f5169, _0x584e33, _0x2c3fb2, _0x23451f, _0x2595f8, _0xb8bdee, _0x5d6523)) && (_0x13d7df(_0x23451f, _0x2d18a1), -0x5 * -0x27e + 0x6a * 0x1e + -0x18e2 === _0x23451f ? (_0x103b18 = _0x2d18a1) : 0x23f1 + -0x4 * 0x8bb + 0x14 * -0xd === _0x23451f ? ((_0x103b18 = _0x2d18a1['init']), (_0x2b9fd3 = _0x2d18a1[_0x1d74f6(0x32b)] || _0x5d6523[_0x1d74f6(0x32b)]), (_0x11479e = _0x2d18a1[_0x1d74f6(0x1e4)] || _0x5d6523[_0x1d74f6(0x1e4)]), (_0x5d6523 = { get: _0x2b9fd3, set: _0x11479e })) : (_0x5d6523 = _0x2d18a1)) else for (var _0x4328fb = _0x4ef3d6[_0x1d74f6(0x259)] - (0xe31 + -0xc5b + -0x1d5); _0x4328fb >= 0x87a + -0xf7c + 0x702; _0x4328fb--) { var _0x5c4cc8 void (0x83b + -0x8af + 0x74) !== (_0x2d18a1 = _0x193050( _0x4ef3d6[_0x4328fb], _0x5f5169, _0x584e33, _0x2c3fb2, _0x23451f, _0x2595f8, _0xb8bdee, _0x5d6523 )) && (_0x13d7df(_0x23451f, _0x2d18a1), -0x4 * 0x511 + -0xc0a * -0x1 + 0x83a === _0x23451f ? (_0x5c4cc8 = _0x2d18a1) : -0x22 * -0x4d + -0x135d * -0x2 + 0x1051 * -0x3 === _0x23451f ? ((_0x5c4cc8 = _0x2d18a1[_0x1d74f6(0x3b9)]), (_0x2b9fd3 = _0x2d18a1[_0x1d74f6(0x32b)] || _0x5d6523[_0x1d74f6(0x32b)]), (_0x11479e = _0x2d18a1[_0x1d74f6(0x1e4)] || _0x5d6523[_0x1d74f6(0x1e4)]), (_0x5d6523 = { get: _0x2b9fd3, set: _0x11479e })) : (_0x5d6523 = _0x2d18a1), void (0x23b9 * 0x1 + 0x2 * -0xccb + -0x5 * 0x207) !== _0x5c4cc8 && (void (-0x15ac + 0x376 + 0x7e * 0x25) === _0x103b18 ? (_0x103b18 = _0x5c4cc8) : _0x1d74f6(0x1ee) == typeof _0x103b18 ? (_0x103b18 = [_0x103b18, _0x5c4cc8]) : _0x103b18['push'](_0x5c4cc8))) } if (-0x11a3 + 0xd * -0x2f2 + -0x67 * -0x8b === _0x23451f || 0xeab * -0x1 + 0x752 * -0x1 + -0x15fe * -0x1 === _0x23451f) { if (void (-0x4a8 * 0x1 + 0xfb0 + -0xb08) === _0x103b18) _0x103b18 = function (_0x1682da, _0x55e4de) { return _0x55e4de } else { if (_0x1d74f6(0x1ee) != typeof _0x103b18) { var _0x278a7c = _0x103b18 _0x103b18 = function (_0x1c32a2, _0x442b39) { var _0x56cde3 = _0x1d74f6 for ( var _0x200043 = _0x442b39, _0x52eaec = 0xc8a + 0x26f6 + 0x20 * -0x19c; _0x52eaec < _0x278a7c[_0x56cde3(0x259)]; _0x52eaec++ ) _0x200043 = _0x278a7c[_0x52eaec]['call'](_0x1c32a2, _0x200043) return _0x200043 } } else { var _0x120537 = _0x103b18 _0x103b18 = function (_0x5a0b99, _0x523966) { var _0x2de49d = _0x1d74f6 return _0x120537[_0x2de49d(0x334)](_0x5a0b99, _0x523966) } } } _0xc8cad8['push'](_0x103b18) } 0x3ac * -0x8 + 0x915 + 0x144b !== _0x23451f && (-0xcde + -0x1f3f + 0x2c1e === _0x23451f ? ((_0x584e33[_0x1d74f6(0x32b)] = _0x5d6523['get']), (_0x584e33[_0x1d74f6(0x1e4)] = _0x5d6523['set'])) : -0x31 * -0xc1 + -0x1 * -0x2388 + -0x4877 === _0x23451f ? (_0x584e33[_0x1d74f6(0x2e4)] = _0x5d6523) : -0x4 * 0x899 + 0x1944 + 0x923 === _0x23451f ? (_0x584e33[_0x1d74f6(0x32b)] = _0x5d6523) : -0x64e * 0x5 + 0x152f + 0xa5b === _0x23451f && (_0x584e33[_0x1d74f6(0x1e4)] = _0x5d6523), _0xb8bdee ? 0x186b + 0x3 * 0x7e9 + -0x1ed * 0x19 === _0x23451f ? (_0xc8cad8[_0x1d74f6(0x36e)](function (_0x1c7663, _0x210e49) { var _0xb35933 = _0x1d74f6 return _0x5d6523['get'][_0xb35933(0x334)](_0x1c7663, _0x210e49) }), _0xc8cad8[_0x1d74f6(0x36e)](function (_0x9ce4a0, _0xa2a6a5) { var _0x548bf5 = _0x1d74f6 return _0x5d6523[_0x548bf5(0x1e4)][_0x548bf5(0x334)](_0x9ce4a0, _0xa2a6a5) })) : -0x2 * 0x91d + -0x226e + 0x282 * 0x15 === _0x23451f ? _0xc8cad8['push'](_0x5d6523) : _0xc8cad8[_0x1d74f6(0x36e)](function (_0x5b9e9b, _0x4ef49d) { return _0x5d6523['call'](_0x5b9e9b, _0x4ef49d) }) : Object[_0x1d74f6(0x175)](_0x5d015f, _0x5f5169, _0x584e33)) } function _0xbbd38b(_0x42478e, _0x1ef3db) { var _0x15d90a = w_0x25f3 _0x1ef3db && _0x42478e[_0x15d90a(0x36e)](function (_0xdfc40e) { var _0x10548c = _0x15d90a for (var _0x3e6f2c = -0x349 * -0xa + 0xe * 0x5b + -0x25d4; _0x3e6f2c < _0x1ef3db[_0x10548c(0x259)]; _0x3e6f2c++) _0x1ef3db[_0x3e6f2c][_0x10548c(0x334)](_0xdfc40e) return _0xdfc40e }) } return function (_0x2327f5, _0x28ca06, _0x53ed99) { var _0x253a06 = [] return ( (function (_0x1816e5, _0x29e49e, _0x48cb46) { var _0x5efef1 = w_0x25f3 for ( var _0x5857a9, _0x48222e, _0x2f7979 = new Map(), _0x2e733e = new Map(), _0x4b6d1a = 0x1 * -0xec3 + 0x1 * 0x6a2 + 0x821; _0x4b6d1a < _0x48cb46[_0x5efef1(0x259)]; _0x4b6d1a++ ) { var _0x58c6d3 = _0x48cb46[_0x4b6d1a] if (Array['isArray'](_0x58c6d3)) { var _0x124b63, _0x4324aa, _0x8c2a39 = _0x58c6d3[-0x1d3a + -0x24ff + 0x423a], _0x8fabbd = _0x58c6d3[0x1b14 + -0x1 * -0x1f0c + -0x1d0f * 0x2], _0x249da3 = _0x58c6d3[_0x5efef1(0x259)] > 0x1 * 0xb42 + -0x1c1 * 0xe + -0x1 * -0xd4f, _0x11d04c = _0x8c2a39 >= -0x12b3 * 0x1 + 0x10e6 + 0x1d2 if ( (_0x11d04c ? ((_0x124b63 = _0x29e49e), -0x15b * -0x5 + 0x373 + -0xa3a != (_0x8c2a39 -= -0x24b2 + -0x12b * 0x17 + 0x3f94) && (_0x4324aa = _0x48222e = _0x48222e || [])) : ((_0x124b63 = _0x29e49e['prototype']), 0x11fa + -0x1859 + 0x65f !== _0x8c2a39 && (_0x4324aa = _0x5857a9 = _0x5857a9 || [])), -0x11df + -0x205d * 0x1 + 0x323c !== _0x8c2a39 && !_0x249da3) ) { var _0x3e0748 = _0x11d04c ? _0x2e733e : _0x2f7979, _0x148749 = _0x3e0748[_0x5efef1(0x32b)](_0x8fabbd) || 0x6c0 + 0x8e3 + 0x1 * -0xfa3 if ( !(-0x288 + -0x1b8f + 0x1e17) === _0x148749 || (0xcae + -0x84a + -0x461 === _0x148749 && 0xebc + -0x6cf + -0x7e9 !== _0x8c2a39) || (0x132d * 0x2 + 0x1 * 0x6ab + -0x1 * 0x2d01 === _0x148749 && 0x2144 + -0xe17 * -0x1 + -0x2f58 !== _0x8c2a39) ) throw new Error( 'Attempted\x20to\x20decorate\x20a\x20public\x20method/accessor\x20that\x20has\x20the\x20same\x20name\x20as\x20a\x20previously\x20decorated\x20public\x20method/accessor.\x20This\x20is\x20not\x20currently\x20supported\x20by\x20the\x20decorators\x20plugin.\x20Property\x20name\x20was:\x20' + _0x8fabbd ) !_0x148749 && _0x8c2a39 > -0x2ea * -0xc + 0x1 * 0x24cb + 0x1 * -0x47c1 ? _0x3e0748[_0x5efef1(0x1e4)](_0x8fabbd, _0x8c2a39) : _0x3e0748[_0x5efef1(0x1e4)](_0x8fabbd, !(0xb9e + -0xc * -0x9d + -0x12fa)) } _0x3345ab(_0x1816e5, _0x124b63, _0x58c6d3, _0x8fabbd, _0x8c2a39, _0x11d04c, _0x249da3, _0x4324aa) } } _0xbbd38b(_0x1816e5, _0x5857a9), _0xbbd38b(_0x1816e5, _0x48222e) })(_0x253a06, _0x2327f5, _0x28ca06), (function (_0x528ea3, _0x4f695c, _0x1527df) { var _0x436c1d = w_0x25f3 if (_0x1527df[_0x436c1d(0x259)] > 0xe5 + 0x269c + -0x2781) { for ( var _0x4e0e1b = [], _0x3eca99 = _0x4f695c, _0x5c69d2 = _0x4f695c[_0x436c1d(0x341)], _0x2abebb = _0x1527df[_0x436c1d(0x259)] - (0x1 * -0x1cbe + 0xa * -0x2ba + 0x3803); _0x2abebb >= 0x8c0 + -0x44d * 0x4 + 0x874; _0x2abebb-- ) { var _0x30122e = { v: !(0x26bb + 0x34c * 0x7 + 0x1 * -0x3dce) } try { var _0x46e0b1 = _0x1527df[_0x2abebb](_0x3eca99, { kind: _0x436c1d(0x19c), name: _0x5c69d2, addInitializer: _0x556aac(_0x4e0e1b, _0x30122e) }) } finally { _0x30122e['v'] = !(0x114e + 0x1f1 * -0x1 + 0x1 * -0xf5d) } void (-0x1 * -0x1c41 + 0x38d * 0x1 + -0x1fce) !== _0x46e0b1 && (_0x13d7df(0x180 + 0x6 * -0x2f + -0x5c, _0x46e0b1), (_0x3eca99 = _0x46e0b1)) } _0x528ea3['push'](_0x3eca99, function () { var _0x1ef0f8 = _0x436c1d for (var _0x337d50 = 0x1 * -0x217d + -0x1a35 + -0x2 * -0x1dd9; _0x337d50 < _0x4e0e1b[_0x1ef0f8(0x259)]; _0x337d50++) _0x4e0e1b[_0x337d50]['call'](_0x3eca99) }) } })(_0x253a06, _0x2327f5, _0x53ed99), _0x253a06 ) } } var _0x15b960, _0x500e9f function _0x4ab133(_0x538caa, _0x1dca3a, _0x362c83) { return (_0x15b960 = _0x15b960 || _0x281b3b())(_0x538caa, _0x1dca3a, _0x362c83) } function _0x4591cd() { function _0x135cea(_0x43f619, _0x5dfa54) { return function (_0x33b776) { var _0x55feea = w_0x25f3 !(function (_0x4d2467, _0x1aaab5) { var _0x188bf8 = w_0x25f3 if (_0x4d2467['v']) throw new Error(_0x188bf8(0x257)) })(_0x5dfa54), _0x23bc0c(_0x33b776, _0x55feea(0x3ba)), _0x43f619[_0x55feea(0x36e)](_0x33b776) } } function _0x39ceae(_0x5713eb, _0x3cd64b, _0x2a5e05, _0x428f9b, _0x1cd0f5, _0x386fff, _0x54211b, _0x40ee96) { var _0x32bd6c = w_0x25f3, _0x43d2aa switch (_0x1cd0f5) { case -0x3 * -0x9f7 + 0x13bc + -0x31a0: _0x43d2aa = _0x32bd6c(0x1b9) break case 0x14f5 + -0x1f56 + -0x1 * -0xa63: _0x43d2aa = _0x32bd6c(0x25a) break case -0x1 * -0x346 + -0xe + 0x335 * -0x1: _0x43d2aa = _0x32bd6c(0x181) break case -0x2 * -0x367 + 0x16b3 + -0x1 * 0x1d7d: _0x43d2aa = _0x32bd6c(0x35d) break default: _0x43d2aa = _0x32bd6c(0x23c) } var _0x1f76cf, _0x2d3a63, _0x52dc9f = { kind: _0x43d2aa, name: _0x54211b ? '#' + _0x3cd64b : _0x3cd64b, static: _0x386fff, private: _0x54211b }, _0x33b885 = { v: !(0x1 * 0xea1 + 0x22b7 + 0x3157 * -0x1) } ; -0x948 + -0x2454 + 0x1c * 0x1a1 !== _0x1cd0f5 && (_0x52dc9f[_0x32bd6c(0x225)] = _0x135cea(_0x428f9b, _0x33b885)), 0xb * 0xb1 + 0x1417 + -0x1bb2 === _0x1cd0f5 ? _0x54211b ? ((_0x1f76cf = _0x2a5e05[_0x32bd6c(0x32b)]), (_0x2d3a63 = _0x2a5e05['set'])) : ((_0x1f76cf = function () { return this[_0x3cd64b] }), (_0x2d3a63 = function (_0x209e9f) { this[_0x3cd64b] = _0x209e9f })) : 0x240f + 0xc11 * 0x3 + -0x22 * 0x220 === _0x1cd0f5 ? (_0x1f76cf = function () { var _0x446fc0 = _0x32bd6c return _0x2a5e05[_0x446fc0(0x2e4)] }) : ((-0x4 * -0x1f6 + 0x1b48 + -0x231f !== _0x1cd0f5 && 0x61 * 0x1a + -0x113 * -0x11 + -0x1c1a !== _0x1cd0f5) || (_0x1f76cf = function () { var _0x447b7b = _0x32bd6c return _0x2a5e05['get'][_0x447b7b(0x334)](this) }), (0x1e4e + 0x25b6 * -0x1 + 0x769 !== _0x1cd0f5 && 0x1397 + -0xb7e + -0x815 !== _0x1cd0f5) || (_0x2d3a63 = function (_0x4c071d) { _0x2a5e05['set']['call'](this, _0x4c071d) })), (_0x52dc9f[_0x32bd6c(0x1d0)] = _0x1f76cf && _0x2d3a63 ? { get: _0x1f76cf, set: _0x2d3a63 } : _0x1f76cf ? { get: _0x1f76cf } : { set: _0x2d3a63 }) try { return _0x5713eb(_0x40ee96, _0x52dc9f) } finally { _0x33b885['v'] = !(-0x8c9 + 0x2 * -0x1189 + 0x2bdb) } } function _0x23bc0c(_0x4aa0f2, _0x12640a) { var _0x1b925e = w_0x25f3 if (_0x1b925e(0x1ee) != typeof _0x4aa0f2) throw new TypeError(_0x12640a + _0x1b925e(0x2f8)) } function _0x2de5e4(_0x3de3bb, _0xa398ec) { var _0xf94308 = w_0x25f3, _0x2c8661 = typeof _0xa398ec if (-0x33 * 0x4c + 0x5 * 0x787 + -0x1 * 0x167e === _0x3de3bb) { if (_0xf94308(0x17d) !== _0x2c8661 || null === _0xa398ec) throw new TypeError(_0xf94308(0x1fd)) void (-0x1e03 + -0x1eb + 0xff7 * 0x2) !== _0xa398ec[_0xf94308(0x32b)] && _0x23bc0c(_0xa398ec[_0xf94308(0x32b)], 'accessor.get'), void (0x3ba + -0x24db + -0xb0b * -0x3) !== _0xa398ec[_0xf94308(0x1e4)] && _0x23bc0c(_0xa398ec[_0xf94308(0x1e4)], _0xf94308(0x231)), void (0x7f8 + -0x1b10 + -0x1318 * -0x1) !== _0xa398ec[_0xf94308(0x3b9)] && _0x23bc0c(_0xa398ec['init'], _0xf94308(0x22f)) } else { if (_0xf94308(0x1ee) !== _0x2c8661) throw new TypeError( (-0xf65 + 0xbd0 + 0x395 === _0x3de3bb ? _0xf94308(0x23c) : 0x48e + -0x1 * 0x1ebe + 0x1a3a === _0x3de3bb ? _0xf94308(0x19c) : _0xf94308(0x25a)) + _0xf94308(0x2cd) ) } } function _0x343a1e(_0xc4b124, _0x1026d8, _0x47c875, _0x150a83, _0x4cdf11, _0x3e4a0b, _0x1dd313, _0x2b027d) { var _0x1c87ab = w_0x25f3, _0x2f46a5, _0x5a2be0, _0x547138, _0x289168, _0x1e1872, _0xd2fd89, _0x17ee52 = _0x47c875[-0x2099 + -0x133 * 0x1 + 0x21cc] if ( (_0x1dd313 ? (_0x2f46a5 = 0xb0a + 0x2125 + -0x2c2f === _0x4cdf11 || 0x12ea + 0x5ba + 0x385 * -0x7 === _0x4cdf11 ? { get: _0x47c875[0x1cf3 + 0x7 * -0x57d + 0x97b], set: _0x47c875[0x6 * 0x210 + -0x2b3 * 0x3 + 0x1 * -0x443] } : 0x1f7b + -0x2 * 0x1253 + 0x52e * 0x1 === _0x4cdf11 ? { get: _0x47c875[0x1476 + 0x23 * -0xb5 + 0x44c] } : 0x2290 + -0x20e6 + -0x1a6 === _0x4cdf11 ? { set: _0x47c875[0x1465 * -0x1 + -0x1 * 0x7d9 + -0x1 * -0x1c41] } : { value: _0x47c875[-0x1550 + 0xb0f + 0xa44] }) : 0x8bb + 0x37b + 0x1 * -0xc36 !== _0x4cdf11 && (_0x2f46a5 = Object[_0x1c87ab(0x2a6)](_0x1026d8, _0x150a83)), -0xf * -0x49 + -0x8c3 * -0x1 + 0xd09 * -0x1 === _0x4cdf11 ? (_0x547138 = { get: _0x2f46a5[_0x1c87ab(0x32b)], set: _0x2f46a5['set'] }) : -0x7c4 + 0x1da9 + -0x15e3 === _0x4cdf11 ? (_0x547138 = _0x2f46a5[_0x1c87ab(0x2e4)]) : 0x7e1 + -0x159a + 0xdbc === _0x4cdf11 ? (_0x547138 = _0x2f46a5[_0x1c87ab(0x32b)]) : 0x105 + 0x177d * 0x1 + 0xbe * -0x21 === _0x4cdf11 && (_0x547138 = _0x2f46a5['set']), _0x1c87ab(0x1ee) == typeof _0x17ee52) ) void (-0x12c9 + 0x3 * -0x2f + 0x1e * 0xa5) !== (_0x289168 = _0x39ceae(_0x17ee52, _0x150a83, _0x2f46a5, _0x2b027d, _0x4cdf11, _0x3e4a0b, _0x1dd313, _0x547138)) && (_0x2de5e4(_0x4cdf11, _0x289168), -0x1cc9 + -0x2 * 0xb5d + 0x1 * 0x3383 === _0x4cdf11 ? (_0x5a2be0 = _0x289168) : -0x1 * 0x1517 + 0x25 * 0x44 + 0xb44 === _0x4cdf11 ? ((_0x5a2be0 = _0x289168[_0x1c87ab(0x3b9)]), (_0x1e1872 = _0x289168[_0x1c87ab(0x32b)] || _0x547138['get']), (_0xd2fd89 = _0x289168[_0x1c87ab(0x1e4)] || _0x547138[_0x1c87ab(0x1e4)]), (_0x547138 = { get: _0x1e1872, set: _0xd2fd89 })) : (_0x547138 = _0x289168)) else for ( var _0x5a46d9 = _0x17ee52[_0x1c87ab(0x259)] - (-0x49 * 0x19 + 0x4a2 + 0x280); _0x5a46d9 >= -0x225b + 0x1562 + 0xcf9; _0x5a46d9-- ) { var _0x60a0d7 void (-0xffd + 0x7 * -0x293 + 0x2202) !== (_0x289168 = _0x39ceae( _0x17ee52[_0x5a46d9], _0x150a83, _0x2f46a5, _0x2b027d, _0x4cdf11, _0x3e4a0b, _0x1dd313, _0x547138 )) && (_0x2de5e4(_0x4cdf11, _0x289168), 0x52 * -0x59 + 0x9 * -0x104 + 0x2 * 0x12d3 === _0x4cdf11 ? (_0x60a0d7 = _0x289168) : -0x1689 + 0x1e96 + -0x80c === _0x4cdf11 ? ((_0x60a0d7 = _0x289168['init']), (_0x1e1872 = _0x289168[_0x1c87ab(0x32b)] || _0x547138['get']), (_0xd2fd89 = _0x289168[_0x1c87ab(0x1e4)] || _0x547138[_0x1c87ab(0x1e4)]), (_0x547138 = { get: _0x1e1872, set: _0xd2fd89 })) : (_0x547138 = _0x289168), void (-0x1a77 + -0x136f + -0xeb * -0x32) !== _0x60a0d7 && (void (-0x519 + -0x1 * -0x1245 + -0x2 * 0x696) === _0x5a2be0 ? (_0x5a2be0 = _0x60a0d7) : _0x1c87ab(0x1ee) == typeof _0x5a2be0 ? (_0x5a2be0 = [_0x5a2be0, _0x60a0d7]) : _0x5a2be0[_0x1c87ab(0x36e)](_0x60a0d7))) } if (0x78c + 0x1d71 * -0x1 + 0x15e5 * 0x1 === _0x4cdf11 || -0x49 * 0x6 + 0x1e * 0xd2 + -0x1 * 0x16e5 === _0x4cdf11) { if (void (0x21db + 0x22d * 0xd + -0x3e24) === _0x5a2be0) _0x5a2be0 = function (_0x5345b0, _0x1a659b) { return _0x1a659b } else { if ('function' != typeof _0x5a2be0) { var _0x336daa = _0x5a2be0 _0x5a2be0 = function (_0x30e05d, _0xf3b4df) { var _0x4d9e7f = _0x1c87ab for ( var _0x362c52 = _0xf3b4df, _0x22ed8a = 0x1 * 0x1f3c + -0x610 + -0x192c; _0x22ed8a < _0x336daa[_0x4d9e7f(0x259)]; _0x22ed8a++ ) _0x362c52 = _0x336daa[_0x22ed8a]['call'](_0x30e05d, _0x362c52) return _0x362c52 } } else { var _0x5aed3b = _0x5a2be0 _0x5a2be0 = function (_0x5dc978, _0x5db160) { return _0x5aed3b['call'](_0x5dc978, _0x5db160) } } } _0xc4b124[_0x1c87ab(0x36e)](_0x5a2be0) } 0x177a + -0xe7 * -0x1c + 0x22 * -0x16f !== _0x4cdf11 && (0x3af + 0x9 * -0x217 + 0x50b * 0x3 === _0x4cdf11 ? ((_0x2f46a5[_0x1c87ab(0x32b)] = _0x547138[_0x1c87ab(0x32b)]), (_0x2f46a5[_0x1c87ab(0x1e4)] = _0x547138[_0x1c87ab(0x1e4)])) : 0x18a3 * -0x1 + 0x263c + -0xd97 === _0x4cdf11 ? (_0x2f46a5[_0x1c87ab(0x2e4)] = _0x547138) : -0x4 * -0x31b + -0x837 * 0x4 + -0x5 * -0x417 === _0x4cdf11 ? (_0x2f46a5[_0x1c87ab(0x32b)] = _0x547138) : -0x1a2e + 0x2 * 0x131d + -0xc08 === _0x4cdf11 && (_0x2f46a5[_0x1c87ab(0x1e4)] = _0x547138), _0x1dd313 ? -0x1 * -0x1757 + 0x1ada + -0x3230 === _0x4cdf11 ? (_0xc4b124[_0x1c87ab(0x36e)](function (_0xb886c1, _0x3a6bf5) { var _0x288d67 = _0x1c87ab return _0x547138[_0x288d67(0x32b)][_0x288d67(0x334)](_0xb886c1, _0x3a6bf5) }), _0xc4b124[_0x1c87ab(0x36e)](function (_0x337452, _0x50608d) { var _0x44b896 = _0x1c87ab return _0x547138[_0x44b896(0x1e4)][_0x44b896(0x334)](_0x337452, _0x50608d) })) : -0x2 * 0x93d + 0x297 + -0x139 * -0xd === _0x4cdf11 ? _0xc4b124['push'](_0x547138) : _0xc4b124[_0x1c87ab(0x36e)](function (_0x1e24c7, _0x120c64) { var _0x3e3294 = _0x1c87ab return _0x547138[_0x3e3294(0x334)](_0x1e24c7, _0x120c64) }) : Object[_0x1c87ab(0x175)](_0x1026d8, _0x150a83, _0x2f46a5)) } function _0x4c3a0d(_0x48207f, _0x257e35) { var _0x1249e7 = w_0x25f3 for ( var _0x47fbbd, _0x402774, _0x333e3a = [], _0xe5fb1e = new Map(), _0x15f194 = new Map(), _0x41a1c1 = -0x1 * 0x575 + -0x13c0 + -0x1b * -0xef; _0x41a1c1 < _0x257e35[_0x1249e7(0x259)]; _0x41a1c1++ ) { var _0x63ddf3 = _0x257e35[_0x41a1c1] if (Array[_0x1249e7(0x2af)](_0x63ddf3)) { var _0x446366, _0x186385, _0x19186f = _0x63ddf3[-0x5bc * 0x4 + 0xf6a * -0x1 + -0x3 * -0xcc9], _0x4911c0 = _0x63ddf3[0x1 * 0x46 + -0xb73 + 0xb2f], _0x39f6a1 = _0x63ddf3['length'] > -0x4 * -0x101 + -0xe6c + 0xa6b, _0x27b8e1 = _0x19186f >= 0xb76 + 0x73 * -0x34 + 0x71 * 0x1b if ( (_0x27b8e1 ? ((_0x446366 = _0x48207f), 0x26c + -0x157d + -0x65b * -0x3 != (_0x19186f -= 0x2324 + 0x27 * 0xbe + -0x4011) && (_0x186385 = _0x402774 = _0x402774 || [])) : ((_0x446366 = _0x48207f[_0x1249e7(0x344)]), -0x7 * 0x297 + 0x1b26 + -0x905 !== _0x19186f && (_0x186385 = _0x47fbbd = _0x47fbbd || [])), 0x13d6 * -0x1 + 0x1 * 0xbb7 + 0x81f !== _0x19186f && !_0x39f6a1) ) { var _0x3f295f = _0x27b8e1 ? _0x15f194 : _0xe5fb1e, _0x566c7b = _0x3f295f[_0x1249e7(0x32b)](_0x4911c0) || -0x188 * -0xb + 0x3e * 0x49 + -0x2286 if ( !(0x903 * -0x1 + -0x1f * -0x8d + 0x1 * -0x810) === _0x566c7b || (-0x43 * 0x5 + -0x1c6c + 0x2f * 0xa2 === _0x566c7b && -0x737 + -0x1ac2 + 0x21fd !== _0x19186f) || (0xdd2 + -0x202b + 0x125d === _0x566c7b && -0x1 * 0x118d + -0x2b8 * -0x3 + 0x8 * 0x12d !== _0x19186f) ) throw new Error( 'Attempted\x20to\x20decorate\x20a\x20public\x20method/accessor\x20that\x20has\x20the\x20same\x20name\x20as\x20a\x20previously\x20decorated\x20public\x20method/accessor.\x20This\x20is\x20not\x20currently\x20supported\x20by\x20the\x20decorators\x20plugin.\x20Property\x20name\x20was:\x20' + _0x4911c0 ) !_0x566c7b && _0x19186f > 0xf * -0x26f + 0x1 * 0x79d + 0x1ce6 * 0x1 ? _0x3f295f[_0x1249e7(0x1e4)](_0x4911c0, _0x19186f) : _0x3f295f['set'](_0x4911c0, !(0x4a * 0x71 + -0xad * 0x2 + 0x6 * -0x538)) } _0x343a1e(_0x333e3a, _0x446366, _0x63ddf3, _0x4911c0, _0x19186f, _0x27b8e1, _0x39f6a1, _0x186385) } } return _0x45d367(_0x333e3a, _0x47fbbd), _0x45d367(_0x333e3a, _0x402774), _0x333e3a } function _0x45d367(_0x59ffc8, _0x5ae59b) { var _0x5b965e = w_0x25f3 _0x5ae59b && _0x59ffc8[_0x5b965e(0x36e)](function (_0x3ed28e) { var _0x5985fb = _0x5b965e for (var _0x5bcc94 = 0x156a + 0x18e0 + -0x2e4a; _0x5bcc94 < _0x5ae59b['length']; _0x5bcc94++) _0x5ae59b[_0x5bcc94][_0x5985fb(0x334)](_0x3ed28e) return _0x3ed28e }) } return function (_0x33b4ae, _0x339d11, _0x5ebc36) { return { e: _0x4c3a0d(_0x33b4ae, _0x339d11), get c() { return (function (_0x92474e, _0x343c16) { var _0x3cc4d2 = w_0x25f3 if (_0x343c16['length'] > -0x271 + -0x2690 + 0x2901) { for ( var _0x18f66c = [], _0x1dd6eb = _0x92474e, _0x1d8833 = _0x92474e[_0x3cc4d2(0x341)], _0x163025 = _0x343c16[_0x3cc4d2(0x259)] - (0x1 * -0x20ed + 0x1f94 + 0x2 * 0xad); _0x163025 >= 0xfba + 0x22 * 0xb6 + 0x27e6 * -0x1; _0x163025-- ) { var _0x49ea6f = { v: !(-0x524 + 0x1a34 + -0x150f) } try { var _0x181a9d = _0x343c16[_0x163025](_0x1dd6eb, { kind: _0x3cc4d2(0x19c), name: _0x1d8833, addInitializer: _0x135cea(_0x18f66c, _0x49ea6f) }) } finally { _0x49ea6f['v'] = !(-0x23e + 0x1 * -0x7fb + 0xa39) } void (-0x1 * -0x253d + -0x23d + -0x80 * 0x46) !== _0x181a9d && (_0x2de5e4(0x4c5 + 0xcaf + -0x2e7 * 0x6, _0x181a9d), (_0x1dd6eb = _0x181a9d)) } return [ _0x1dd6eb, function () { var _0x543396 = _0x3cc4d2 for (var _0x2a7175 = -0xe71 * -0x1 + 0x24c0 + -0xa3d * 0x5; _0x2a7175 < _0x18f66c['length']; _0x2a7175++) _0x18f66c[_0x2a7175][_0x543396(0x334)](_0x1dd6eb) } ] } })(_0x33b4ae, _0x5ebc36) } } } } function _0x49af1f(_0x3a86ea, _0x270f72, _0x219a67) { return (_0x49af1f = _0x4591cd())(_0x3a86ea, _0x270f72, _0x219a67) } function _0x3e4ff5(_0x5b206b, _0xdfb3e7) { return function (_0x19bdbd) { var _0x1caf0f = w_0x25f3 _0x15eb90(_0xdfb3e7, _0x1caf0f(0x225)), _0x45d8b1(_0x19bdbd, _0x1caf0f(0x3ba)), _0x5b206b[_0x1caf0f(0x36e)](_0x19bdbd) } } function _0x19207d(_0x45ced6, _0xcee03f) { var _0x41489e = w_0x25f3 if (!_0x45ced6(_0xcee03f)) throw new TypeError(_0x41489e(0x255)) } function _0x151762(_0x535a19, _0x4e0a69, _0x270f96, _0x52f7e9, _0x23d388, _0x49094d, _0x49f620, _0x251987, _0x40c067) { var _0x3b49d7 = w_0x25f3, _0x5d54d8 switch (_0x23d388) { case -0x14b9 + 0x1dd5 + -0x91b: _0x5d54d8 = _0x3b49d7(0x1b9) break case -0xe4a + 0x12be + -0x472: _0x5d54d8 = _0x3b49d7(0x25a) break case -0x10f1 * -0x2 + 0x179 * 0x19 + -0x46b0: _0x5d54d8 = _0x3b49d7(0x181) break case 0x3 * -0x5cf + 0x778 * 0x1 + 0x353 * 0x3: _0x5d54d8 = _0x3b49d7(0x35d) break default: _0x5d54d8 = _0x3b49d7(0x23c) } var _0x246ff5, _0x4e02d1, _0x45ccfd = { kind: _0x5d54d8, name: _0x49f620 ? '#' + _0x4e0a69 : _0x4e0a69, static: _0x49094d, private: _0x49f620 }, _0x4733a4 = { v: !(-0xad5 + 0x1f * -0x59 + -0x1f7 * -0xb) } if ( (0xcf6 + 0x1e15 + -0x3 * 0xe59 !== _0x23d388 && (_0x45ccfd[_0x3b49d7(0x225)] = _0x3e4ff5(_0x52f7e9, _0x4733a4)), _0x49f620 || (-0x112e + -0x23ab + 0x34d9 !== _0x23d388 && 0xa00 + -0x234a + 0x194c !== _0x23d388)) ) { if (-0x327 * -0x2 + -0xb00 + 0x4b4 === _0x23d388) _0x246ff5 = function (_0x36bc44) { var _0x2d48fd = _0x3b49d7 return _0x19207d(_0x40c067, _0x36bc44), _0x270f96[_0x2d48fd(0x2e4)] } else { var _0x339c00 = -0x1746 + -0x1bb + 0xad * 0x25 === _0x23d388 || -0x859 + 0x4 * -0xe2 + -0x27 * -0x4e === _0x23d388 ; (_0x339c00 || 0x5 * -0x3bf + -0x1d90 + 0x304e === _0x23d388) && (_0x246ff5 = _0x49f620 ? function (_0x26da64) { var _0x21bb3a = _0x3b49d7 return _0x19207d(_0x40c067, _0x26da64), _0x270f96['get'][_0x21bb3a(0x334)](_0x26da64) } : function (_0x2ac873) { var _0xa2fd4f = _0x3b49d7 return _0x270f96[_0xa2fd4f(0x32b)][_0xa2fd4f(0x334)](_0x2ac873) }), (_0x339c00 || -0x14c4 * 0x1 + -0x231e + -0xb2e * -0x5 === _0x23d388) && (_0x4e02d1 = _0x49f620 ? function (_0x1e61ca, _0x1c77b0) { var _0x5f2230 = _0x3b49d7 _0x19207d(_0x40c067, _0x1e61ca), _0x270f96[_0x5f2230(0x1e4)][_0x5f2230(0x334)](_0x1e61ca, _0x1c77b0) } : function (_0x4d5a08, _0x3ac6c6) { var _0x1baec7 = _0x3b49d7 _0x270f96[_0x1baec7(0x1e4)][_0x1baec7(0x334)](_0x4d5a08, _0x3ac6c6) }) } } else (_0x246ff5 = function (_0x4ff2b5) { return _0x4ff2b5[_0x4e0a69] }), -0x20ec + 0x12ee * 0x2 + -0x4f0 === _0x23d388 && (_0x4e02d1 = function (_0x2f8383, _0x4a22e5) { _0x2f8383[_0x4e0a69] = _0x4a22e5 }) var _0x557c63 = _0x49f620 ? _0x40c067[_0x3b49d7(0x301)]() : function (_0x2f4445) { return _0x4e0a69 in _0x2f4445 } _0x45ccfd[_0x3b49d7(0x1d0)] = _0x246ff5 && _0x4e02d1 ? { get: _0x246ff5, set: _0x4e02d1, has: _0x557c63 } : _0x246ff5 ? { get: _0x246ff5, has: _0x557c63 } : { set: _0x4e02d1, has: _0x557c63 } try { return _0x535a19(_0x251987, _0x45ccfd) } finally { _0x4733a4['v'] = !(0xea8 + -0xe9f * 0x1 + 0x1 * -0x9) } } function _0x15eb90(_0x202051, _0x1c2373) { var _0x51521b = w_0x25f3 if (_0x202051['v']) throw new Error('attempted\x20to\x20call\x20' + _0x1c2373 + _0x51521b(0x168)) } function _0x45d8b1(_0x2ad532, _0x423791) { var _0x14562d = w_0x25f3 if (_0x14562d(0x1ee) != typeof _0x2ad532) throw new TypeError(_0x423791 + _0x14562d(0x2f8)) } function _0xed525b(_0x522a86, _0x4177e1) { var _0x442324 = w_0x25f3, _0x399204 = typeof _0x4177e1 if (-0x361 + 0x3 * 0x2c4 + 0x4ea * -0x1 === _0x522a86) { if (_0x442324(0x17d) !== _0x399204 || null === _0x4177e1) throw new TypeError(_0x442324(0x1fd)) void (-0x4a0 + 0x2e8 + 0x1b8) !== _0x4177e1[_0x442324(0x32b)] && _0x45d8b1(_0x4177e1[_0x442324(0x32b)], _0x442324(0x170)), void (0xc4 * -0x1d + 0x651 + 0xfe3) !== _0x4177e1['set'] && _0x45d8b1(_0x4177e1[_0x442324(0x1e4)], _0x442324(0x231)), void (-0x168c + 0x16b5 * 0x1 + 0x29 * -0x1) !== _0x4177e1['init'] && _0x45d8b1(_0x4177e1[_0x442324(0x3b9)], _0x442324(0x22f)) } else { if (_0x442324(0x1ee) !== _0x399204) throw new TypeError( (0x20d7 + 0x7 * -0x362 + 0x7 * -0x14f === _0x522a86 ? _0x442324(0x23c) : 0x1 * -0x1257 + -0x2d9 + -0x26 * -0x8f === _0x522a86 ? 'class' : 'method') + '\x20decorators\x20must\x20return\x20a\x20function\x20or\x20void\x200' ) } } function _0x244c39(_0x17683) { return function () { return _0x17683(this) } } function _0x48532c(_0x5503e0) { return function (_0x23d6a1) { _0x5503e0(this, _0x23d6a1) } } function _0x23e6b(_0x5cf198, _0x5646db, _0x26f9f9, _0x37f54b, _0x47565f, _0x2aa948, _0xccabc1, _0x5c3a48, _0x9ffbdc) { var _0x3e2adf = w_0x25f3, _0x592aeb, _0x365a6e, _0x4e8d10, _0x589008, _0x17d95a, _0x11c9ab, _0x9a7bbd = _0x26f9f9[0xa46 + 0xb3c + -0x1582] if ( (_0xccabc1 ? (_0x592aeb = 0x24 * 0x47 + 0xf85 + -0x1981 === _0x47565f || 0x14ca + -0x1099 + 0x218 * -0x2 === _0x47565f ? { get: _0x244c39(_0x26f9f9[0x7 * -0x2f0 + 0x227b + -0xde8]), set: _0x48532c(_0x26f9f9[-0xad * -0x19 + -0xc3c + 0x29 * -0x1d]) } : 0x1b99 * -0x1 + 0x367 + -0x1 * -0x1835 === _0x47565f ? { get: _0x26f9f9[0xb1 * 0x22 + 0x3 * 0xcef + -0x24 * 0x1bb] } : 0x1 * -0x10f + -0x1 * -0x2023 + -0x1f10 === _0x47565f ? { set: _0x26f9f9[0x36 * -0xa6 + -0x1cb2 + 0x3fb9] } : { value: _0x26f9f9[-0x7ba * 0x1 + 0x1850 + -0x1093] }) : -0x2 * 0x713 + 0x26fe + 0x27c * -0xa !== _0x47565f && (_0x592aeb = Object[_0x3e2adf(0x2a6)](_0x5646db, _0x37f54b)), -0x1982 + 0x1947 + 0x14 * 0x3 === _0x47565f ? (_0x4e8d10 = { get: _0x592aeb[_0x3e2adf(0x32b)], set: _0x592aeb[_0x3e2adf(0x1e4)] }) : 0xe9b + -0x2a3 + 0x5fb * -0x2 === _0x47565f ? (_0x4e8d10 = _0x592aeb['value']) : -0x13 * -0x5b + 0x17cb + -0x1 * 0x1e89 === _0x47565f ? (_0x4e8d10 = _0x592aeb[_0x3e2adf(0x32b)]) : 0x7d7 * -0x1 + 0x5 * 0x81 + 0x556 === _0x47565f && (_0x4e8d10 = _0x592aeb['set']), 'function' == typeof _0x9a7bbd) ) void (0x1 * 0x1ee3 + 0xd + -0x1ef0) !== (_0x589008 = _0x151762(_0x9a7bbd, _0x37f54b, _0x592aeb, _0x5c3a48, _0x47565f, _0x2aa948, _0xccabc1, _0x4e8d10, _0x9ffbdc)) && (_0xed525b(_0x47565f, _0x589008), 0xc91 * -0x1 + -0x893 * -0x1 + 0x3fe === _0x47565f ? (_0x365a6e = _0x589008) : -0x1 * 0x21dd + -0x109 * -0x24 + -0x366 === _0x47565f ? ((_0x365a6e = _0x589008[_0x3e2adf(0x3b9)]), (_0x17d95a = _0x589008[_0x3e2adf(0x32b)] || _0x4e8d10[_0x3e2adf(0x32b)]), (_0x11c9ab = _0x589008['set'] || _0x4e8d10[_0x3e2adf(0x1e4)]), (_0x4e8d10 = { get: _0x17d95a, set: _0x11c9ab })) : (_0x4e8d10 = _0x589008)) else for (var _0x4f1458 = _0x9a7bbd['length'] - (0x204c + 0x277 * 0x7 + -0xe * 0x38a); _0x4f1458 >= -0x23c2 + 0x91 + 0x2331; _0x4f1458--) { var _0x189ac8 void (-0x18f8 * -0x1 + -0x143a + -0x1 * 0x4be) !== (_0x589008 = _0x151762( _0x9a7bbd[_0x4f1458], _0x37f54b, _0x592aeb, _0x5c3a48, _0x47565f, _0x2aa948, _0xccabc1, _0x4e8d10, _0x9ffbdc )) && (_0xed525b(_0x47565f, _0x589008), -0x22cb + -0x2043 * -0x1 + 0x288 === _0x47565f ? (_0x189ac8 = _0x589008) : 0x1bd * -0x3 + 0x283 * 0x8 + 0x2 * -0x770 === _0x47565f ? ((_0x189ac8 = _0x589008[_0x3e2adf(0x3b9)]), (_0x17d95a = _0x589008[_0x3e2adf(0x32b)] || _0x4e8d10[_0x3e2adf(0x32b)]), (_0x11c9ab = _0x589008[_0x3e2adf(0x1e4)] || _0x4e8d10['set']), (_0x4e8d10 = { get: _0x17d95a, set: _0x11c9ab })) : (_0x4e8d10 = _0x589008), void (-0xaeb + 0x1 * 0x1bb3 + 0x4 * -0x432) !== _0x189ac8 && (void (-0x2359 + -0x3 * -0x323 + 0x19f0) === _0x365a6e ? (_0x365a6e = _0x189ac8) : _0x3e2adf(0x1ee) == typeof _0x365a6e ? (_0x365a6e = [_0x365a6e, _0x189ac8]) : _0x365a6e[_0x3e2adf(0x36e)](_0x189ac8))) } if (0x21ee + -0x129b + 0xf53 * -0x1 === _0x47565f || -0x44d * -0x7 + -0xa27 + -0x13f3 * 0x1 === _0x47565f) { if (void (0x10 * -0x218 + -0x707 * 0x1 + 0x2887) === _0x365a6e) _0x365a6e = function (_0x56b70b, _0x5e4d55) { return _0x5e4d55 } else { if (_0x3e2adf(0x1ee) != typeof _0x365a6e) { var _0x3101a1 = _0x365a6e _0x365a6e = function (_0x449bbf, _0x5196d8) { var _0x360050 = _0x3e2adf for ( var _0x143a4f = _0x5196d8, _0x36e4b1 = -0x1ef8 + -0x3 * -0xd01 + -0x80b * 0x1; _0x36e4b1 < _0x3101a1[_0x360050(0x259)]; _0x36e4b1++ ) _0x143a4f = _0x3101a1[_0x36e4b1][_0x360050(0x334)](_0x449bbf, _0x143a4f) return _0x143a4f } } else { var _0x1e2902 = _0x365a6e _0x365a6e = function (_0xe6998d, _0xec7c91) { var _0x5bb1b6 = _0x3e2adf return _0x1e2902[_0x5bb1b6(0x334)](_0xe6998d, _0xec7c91) } } } _0x5cf198['push'](_0x365a6e) } 0x82e + 0x14c5 + -0x1cf3 !== _0x47565f && (-0x1 * -0x1d72 + 0x15b0 + 0x3 * -0x110b === _0x47565f ? ((_0x592aeb[_0x3e2adf(0x32b)] = _0x4e8d10[_0x3e2adf(0x32b)]), (_0x592aeb['set'] = _0x4e8d10['set'])) : 0x1de7 + -0x16 * -0x10a + -0x34c1 === _0x47565f ? (_0x592aeb[_0x3e2adf(0x2e4)] = _0x4e8d10) : -0x2508 + -0x2665 + 0x4b70 === _0x47565f ? (_0x592aeb[_0x3e2adf(0x32b)] = _0x4e8d10) : 0x11 * -0x9f + -0x6a5 + 0x1138 === _0x47565f && (_0x592aeb[_0x3e2adf(0x1e4)] = _0x4e8d10), _0xccabc1 ? 0x8f6 * 0x1 + -0xae9 + 0xa * 0x32 === _0x47565f ? (_0x5cf198['push'](function (_0x31015b, _0x979f27) { var _0x1938a1 = _0x3e2adf return _0x4e8d10['get'][_0x1938a1(0x334)](_0x31015b, _0x979f27) }), _0x5cf198[_0x3e2adf(0x36e)](function (_0x506584, _0x44c428) { var _0x29e7e5 = _0x3e2adf return _0x4e8d10['set'][_0x29e7e5(0x334)](_0x506584, _0x44c428) })) : 0x27 * -0xd0 + 0x4 * -0x12d + 0x2466 === _0x47565f ? _0x5cf198[_0x3e2adf(0x36e)](_0x4e8d10) : _0x5cf198[_0x3e2adf(0x36e)](function (_0x3345b4, _0x845662) { var _0x1b7734 = _0x3e2adf return _0x4e8d10[_0x1b7734(0x334)](_0x3345b4, _0x845662) }) : Object['defineProperty'](_0x5646db, _0x37f54b, _0x592aeb)) } function _0x754898(_0x2bd2c5, _0x2c3dcd, _0x119780) { var _0x42b3ee = w_0x25f3 for ( var _0x328f7d, _0x12addf, _0x29a079, _0x3330d8 = [], _0x484293 = new Map(), _0x4a2ea8 = new Map(), _0x478e5d = 0x1 * -0x3e1 + -0x22b8 + 0x2699; _0x478e5d < _0x2c3dcd[_0x42b3ee(0x259)]; _0x478e5d++ ) { var _0x5c7927 = _0x2c3dcd[_0x478e5d] if (Array[_0x42b3ee(0x2af)](_0x5c7927)) { var _0x25ea34, _0x5b9b12, _0x35b641 = _0x5c7927[-0x33b * 0x1 + 0xebe + 0x3 * -0x3d6], _0x49a803 = _0x5c7927[-0x78a + -0x29 * 0x60 + 0xc * 0x1e9], _0x410da0 = _0x5c7927[_0x42b3ee(0x259)] > 0x1291 + -0x1e03 + 0xb75, _0x3c9168 = _0x35b641 >= -0x13e1 * 0x1 + 0x793 + -0x5 * -0x277, _0x41ada5 = _0x119780 if ( (_0x3c9168 ? ((_0x25ea34 = _0x2bd2c5), -0x7e3 + -0x1087 * 0x2 + 0x28f1 != (_0x35b641 -= 0x867 + 0xa1b + 0x127d * -0x1) && (_0x5b9b12 = _0x12addf = _0x12addf || []), _0x410da0 && !_0x29a079 && (_0x29a079 = function (_0x106ee5) { return _0x37e1e2(_0x106ee5) === _0x2bd2c5 }), (_0x41ada5 = _0x29a079)) : ((_0x25ea34 = _0x2bd2c5['prototype']), 0x13a3 * 0x1 + -0x2589 + 0x11e6 * 0x1 !== _0x35b641 && (_0x5b9b12 = _0x328f7d = _0x328f7d || [])), 0xfad + 0x3 * -0xceb + 0x1714 !== _0x35b641 && !_0x410da0) ) { var _0x4430b1 = _0x3c9168 ? _0x4a2ea8 : _0x484293, _0x3a9a47 = _0x4430b1[_0x42b3ee(0x32b)](_0x49a803) || 0x139e + -0xa * 0x13d + -0x73c if ( !(-0x1 * 0x5df + 0x94b + -0x36c) === _0x3a9a47 || (0x3 * 0x38 + -0x25b * 0x7 + -0x8 * -0x1fb === _0x3a9a47 && 0x54 + 0x152e + -0x2a * 0x83 !== _0x35b641) || (0x2 * -0x1cb + 0x1e71 + -0x1ad7 * 0x1 === _0x3a9a47 && 0x6e9 + 0xa71 + 0xc1 * -0x17 !== _0x35b641) ) throw new Error( 'Attempted\x20to\x20decorate\x20a\x20public\x20method/accessor\x20that\x20has\x20the\x20same\x20name\x20as\x20a\x20previously\x20decorated\x20public\x20method/accessor.\x20This\x20is\x20not\x20currently\x20supported\x20by\x20the\x20decorators\x20plugin.\x20Property\x20name\x20was:\x20' + _0x49a803 ) !_0x3a9a47 && _0x35b641 > -0x73 * -0x45 + 0x798 + -0x2695 ? _0x4430b1['set'](_0x49a803, _0x35b641) : _0x4430b1['set'](_0x49a803, !(0x1 * 0xb7c + -0x15ce * 0x1 + 0xa52)) } _0x23e6b(_0x3330d8, _0x25ea34, _0x5c7927, _0x49a803, _0x35b641, _0x3c9168, _0x410da0, _0x5b9b12, _0x41ada5) } } return _0xdfc9aa(_0x3330d8, _0x328f7d), _0xdfc9aa(_0x3330d8, _0x12addf), _0x3330d8 } function _0xdfc9aa(_0x18680e, _0x994303) { var _0x3df611 = w_0x25f3 _0x994303 && _0x18680e[_0x3df611(0x36e)](function (_0x3720d6) { var _0xc905ee = _0x3df611 for (var _0x400047 = 0x17dc + -0x3df * 0x6 + -0xa2; _0x400047 < _0x994303['length']; _0x400047++) _0x994303[_0x400047][_0xc905ee(0x334)](_0x3720d6) return _0x3720d6 }) } function _0x2258b9(_0x31d7ec, _0x22dcdb) { var _0x41474b = w_0x25f3 if (_0x22dcdb[_0x41474b(0x259)] > 0x26a0 + -0x145f + -0x1241) { for ( var _0x3c54e9 = [], _0x8cb428 = _0x31d7ec, _0x2344cd = _0x31d7ec['name'], _0x16f8af = _0x22dcdb[_0x41474b(0x259)] - (0x1321 + 0x1388 + 0x1354 * -0x2); _0x16f8af >= 0x1a79 + 0x6f * 0x2a + -0x2caf; _0x16f8af-- ) { var _0x36735e = { v: !(0x4 * -0x601 + 0x116d * 0x1 + -0x698 * -0x1) } try { var _0x147e7c = _0x22dcdb[_0x16f8af](_0x8cb428, { kind: _0x41474b(0x19c), name: _0x2344cd, addInitializer: _0x3e4ff5(_0x3c54e9, _0x36735e) }) } finally { _0x36735e['v'] = !(0x1e88 + -0x1973 + -0x515 * 0x1) } void (-0xedb + -0x5 * 0x2bf + 0x1c96) !== _0x147e7c && (_0xed525b(0x10b8 + -0xb * 0x2e1 + -0x3 * -0x4ff, _0x147e7c), (_0x8cb428 = _0x147e7c)) } return [ _0x8cb428, function () { var _0x28afa7 = _0x41474b for (var _0x4967c5 = -0x1 * 0x23b5 + -0x2 * -0x4c7 + 0x203 * 0xd; _0x4967c5 < _0x3c54e9[_0x28afa7(0x259)]; _0x4967c5++) _0x3c54e9[_0x4967c5][_0x28afa7(0x334)](_0x8cb428) } ] } } function _0x499d65(_0x2be690, _0x428d43, _0x381e26, _0x409a13) { return { e: _0x754898(_0x2be690, _0x428d43, _0x409a13), get c() { return _0x2258b9(_0x2be690, _0x381e26) } } } function _0x63f01f(_0x5fd149) { var _0x2e1243 = w_0x25f3, _0x111c4c = {}, _0x2aa094 = !(-0x3d * -0x53 + -0x2086 * -0x1 + -0x344c) function _0x3ad3fe(_0x4a2256, _0x3bcff1) { return ( (_0x2aa094 = !(0x160 * 0x3 + -0x4b5 * 0x1 + 0x1 * 0x95)), { done: !(0x1cd3 + 0x1 * -0xa11 + -0x12c1 * 0x1), value: new _0x59d886( (_0x3bcff1 = new Promise(function (_0x353966) { _0x353966(_0x5fd149[_0x4a2256](_0x3bcff1)) })), 0x2b * 0x44 + -0x8b3 * 0x2 + 0x1 * 0x5fb ) } ) } return ( (_0x111c4c[(_0x2e1243(0x384) != typeof Symbol && Symbol['iterator']) || _0x2e1243(0x1dd)] = function () { return this }), (_0x111c4c[_0x2e1243(0x389)] = function (_0x45912d) { return _0x2aa094 ? ((_0x2aa094 = !(0x1569 + 0x7 * 0x314 + -0x2af4)), _0x45912d) : _0x3ad3fe('next', _0x45912d) }), _0x2e1243(0x1ee) == typeof _0x5fd149[_0x2e1243(0x250)] && (_0x111c4c[_0x2e1243(0x250)] = function (_0xd71e81) { var _0x37886e = _0x2e1243 if (_0x2aa094) throw ((_0x2aa094 = !(-0x648 + -0x1eca + -0x2513 * -0x1)), _0xd71e81) return _0x3ad3fe(_0x37886e(0x250), _0xd71e81) }), _0x2e1243(0x1ee) == typeof _0x5fd149[_0x2e1243(0x2fd)] && (_0x111c4c[_0x2e1243(0x2fd)] = function (_0xd4b711) { return _0x2aa094 ? ((_0x2aa094 = !(-0x8e1 * -0x4 + -0x2194 + 0x3 * -0xa5)), _0xd4b711) : _0x3ad3fe('return', _0xd4b711) }), _0x111c4c ) } function _0x278b9f(_0x12b945) { var _0x55cd1f = w_0x25f3, _0x449dfe, _0x31b182, _0x218f32, _0x2ecb8a = -0x1d9 * -0x5 + -0x5d4 + -0x367 for ('undefined' != typeof Symbol && ((_0x31b182 = Symbol[_0x55cd1f(0x17c)]), (_0x218f32 = Symbol[_0x55cd1f(0x3b3)])); _0x2ecb8a--;) { if (_0x31b182 && null != (_0x449dfe = _0x12b945[_0x31b182])) return _0x449dfe[_0x55cd1f(0x334)](_0x12b945) if (_0x218f32 && null != (_0x449dfe = _0x12b945[_0x218f32])) return new _0x3d6fc9(_0x449dfe[_0x55cd1f(0x334)](_0x12b945)) ; (_0x31b182 = _0x55cd1f(0x230)), (_0x218f32 = _0x55cd1f(0x1dd)) } throw new TypeError(_0x55cd1f(0x2a9)) } function _0x3d6fc9(_0x4d37b6) { var _0x36b1b0 = w_0x25f3 function _0x6c368b(_0x231d6c) { var _0x3a3e78 = w_0x25f3 if (Object(_0x231d6c) !== _0x231d6c) return Promise['reject'](new TypeError(_0x231d6c + _0x3a3e78(0x3a6))) var _0x4cdd04 = _0x231d6c[_0x3a3e78(0x1e3)] return Promise['resolve'](_0x231d6c[_0x3a3e78(0x2e4)])['then'](function (_0x468cc1) { return { value: _0x468cc1, done: _0x4cdd04 } }) } return ( ((_0x3d6fc9 = function (_0x5a83bf) { var _0x2ffee8 = w_0x25f3 ; (this['s'] = _0x5a83bf), (this['n'] = _0x5a83bf[_0x2ffee8(0x389)]) })[_0x36b1b0(0x344)] = { s: null, n: null, next: function () { var _0x1eac7c = _0x36b1b0 return _0x6c368b(this['n'][_0x1eac7c(0x207)](this['s'], arguments)) }, return: function (_0x379438) { var _0x45dc23 = _0x36b1b0, _0x35ef86 = this['s'][_0x45dc23(0x2fd)] return void (0x23cd + 0x6f3 * 0x1 + -0x48 * 0x98) === _0x35ef86 ? Promise[_0x45dc23(0x278)]({ value: _0x379438, done: !(-0x220 + -0x16b0 + 0x8 * 0x31a) }) : _0x6c368b(_0x35ef86[_0x45dc23(0x207)](this['s'], arguments)) }, throw: function (_0x2ca86a) { var _0x5812c4 = _0x36b1b0, _0x449ee5 = this['s'][_0x5812c4(0x2fd)] return void (0xe3b + 0x1 * -0x128e + 0x453) === _0x449ee5 ? Promise[_0x5812c4(0x39b)](_0x2ca86a) : _0x6c368b(_0x449ee5['apply'](this['s'], arguments)) } }), new _0x3d6fc9(_0x4d37b6) ) } function _0x81c36b(_0x305287) { return new _0x59d886(_0x305287, -0x5e + 0xf84 + -0xf26 * 0x1) } function _0x37e1e2(_0x3127ce) { var _0x43b88e = w_0x25f3 if (Object(_0x3127ce) !== _0x3127ce) throw TypeError( 'right-hand\x20side\x20of\x20\x27in\x27\x20should\x20be\x20an\x20object,\x20got\x20' + (null !== _0x3127ce ? typeof _0x3127ce : _0x43b88e(0x308)) ) return _0x3127ce } function _0x564673(_0x18bd7c, _0x51fb0f, _0x2103c5, _0x5f4619) { var _0x41c64 = w_0x25f3, _0xab8c16 = { configurable: !(-0x15c4 + 0x25f7 * -0x1 + 0x3bbb), enumerable: !(0x2581 + -0x121c + -0x1365) } return (_0xab8c16[_0x18bd7c] = _0x5f4619), Object[_0x41c64(0x175)](_0x51fb0f, _0x2103c5, _0xab8c16) } function _0x19d66a(_0x14c297, _0x128d38) { var _0x48eab4 = w_0x25f3, _0x25f943 = null == _0x14c297 ? null : (_0x48eab4(0x384) != typeof Symbol && _0x14c297[Symbol[_0x48eab4(0x3b3)]]) || _0x14c297[_0x48eab4(0x1dd)] if (null != _0x25f943) { var _0x285958, _0x5bcc9e, _0x2d4c39, _0x193c70, _0x146015 = [], _0x16efb7 = !(-0x7e * 0x36 + 0xcff * 0x1 + 0xd95), _0x5c9556 = !(-0x1d71 * -0x1 + 0x434 * -0x9 + 0x864) try { if ( ((_0x2d4c39 = (_0x25f943 = _0x25f943[_0x48eab4(0x334)](_0x14c297))['next']), -0xe3 * -0xb + -0x1f3 * 0xe + -0x43 * -0x43 === _0x128d38) ) { if (Object(_0x25f943) !== _0x25f943) return _0x16efb7 = !(0x17cb + 0x18a9 + -0x4f * 0x9d) } else { for ( ; !(_0x16efb7 = (_0x285958 = _0x2d4c39['call'](_0x25f943))[_0x48eab4(0x1e3)]) && (_0x146015[_0x48eab4(0x36e)](_0x285958[_0x48eab4(0x2e4)]), _0x146015[_0x48eab4(0x259)] !== _0x128d38); _0x16efb7 = !(0x1 * -0x22d3 + 0x1f2e + 0x3 * 0x137) ); } } catch (_0x22e14d) { ; (_0x5c9556 = !(-0x3 * -0x69e + -0xd79 + -0x47 * 0x17)), (_0x5bcc9e = _0x22e14d) } finally { try { if ( !_0x16efb7 && null != _0x25f943[_0x48eab4(0x2fd)] && ((_0x193c70 = _0x25f943['return']()), Object(_0x193c70) !== _0x193c70) ) return } finally { if (_0x5c9556) throw _0x5bcc9e } } return _0x146015 } } function _0x376fd5(_0x233550, _0x1b337f) { var _0x545ac4 = w_0x25f3, _0x524438 = _0x233550 && ((_0x545ac4(0x384) != typeof Symbol && _0x233550[Symbol[_0x545ac4(0x3b3)]]) || _0x233550['@@iterator']) if (null != _0x524438) { var _0x259ce6, _0x4523ee = [] for ( _0x524438 = _0x524438['call'](_0x233550); _0x233550[_0x545ac4(0x259)] < _0x1b337f && !(_0x259ce6 = _0x524438['next']())[_0x545ac4(0x1e3)]; ) _0x4523ee[_0x545ac4(0x36e)](_0x259ce6['value']) return _0x4523ee } } function _0x2e4b86(_0x760974, _0x438efa, _0x37a20b, _0x52b279) { var _0x2644f8 = w_0x25f3 _0x500e9f || (_0x500e9f = (_0x2644f8(0x1ee) == typeof Symbol && Symbol[_0x2644f8(0x31e)] && Symbol[_0x2644f8(0x31e)](_0x2644f8(0x279))) || 0x1353f + -0x1157 + -0x3921) var _0x513b54 = _0x760974 && _0x760974[_0x2644f8(0x371)], _0x5469e9 = arguments[_0x2644f8(0x259)] - (-0xcb * -0xb + -0xa * 0x137 + -0x28 * -0x16) if ( (_0x438efa || 0x109 * -0x1c + 0xdc1 + 0xf3b === _0x5469e9 || (_0x438efa = { children: void (-0x2 * -0x1037 + 0x32f + -0x239d) }), -0xf69 + 0xedb + -0x8f * -0x1 === _0x5469e9) ) _0x438efa[_0x2644f8(0x16f)] = _0x52b279 else { if (_0x5469e9 > -0x18e2 + -0x25af + 0x3e92) { for (var _0x5c6f82 = new Array(_0x5469e9), _0x63cb90 = -0x1 * -0xebd + -0x1a37 + 0x2 * 0x5bd; _0x63cb90 < _0x5469e9; _0x63cb90++) _0x5c6f82[_0x63cb90] = arguments[_0x63cb90 + (0x15f5 + -0x245f + -0x4cf * -0x3)] _0x438efa[_0x2644f8(0x16f)] = _0x5c6f82 } } if (_0x438efa && _0x513b54) { for (var _0xbcee2c in _0x513b54) void (-0x1091 * -0x1 + -0x3 * 0x34d + -0x6aa) === _0x438efa[_0xbcee2c] && (_0x438efa[_0xbcee2c] = _0x513b54[_0xbcee2c]) } else _0x438efa || (_0x438efa = _0x513b54 || {}) return { $$typeof: _0x500e9f, type: _0x760974, key: void (-0x7 * 0x1cd + -0x1 * -0xb38 + 0x163) === _0x37a20b ? null : '' + _0x37a20b, ref: null, props: _0x438efa, _owner: null } } function _0x3a3eb5(_0x4619be, _0x3fc822) { var _0x44978d = w_0x25f3, _0x504f59 = Object[_0x44978d(0x17f)](_0x4619be) if (Object[_0x44978d(0x388)]) { var _0x4ea700 = Object['getOwnPropertySymbols'](_0x4619be) _0x3fc822 && (_0x4ea700 = _0x4ea700[_0x44978d(0x164)](function (_0x2a0c03) { var _0x162328 = _0x44978d return Object[_0x162328(0x2a6)](_0x4619be, _0x2a0c03)[_0x162328(0x23a)] })), _0x504f59['push'][_0x44978d(0x207)](_0x504f59, _0x4ea700) } return _0x504f59 } function _0x4ee2dd(_0xf371f0) { var _0x145ce6 = w_0x25f3 for (var _0x5e36a1 = -0x5 * 0x1ad + 0x11e6 * -0x1 + 0x1a48; _0x5e36a1 < arguments[_0x145ce6(0x259)]; _0x5e36a1++) { var _0xdb889d = null != arguments[_0x5e36a1] ? arguments[_0x5e36a1] : {} _0x5e36a1 % (0x1174 + 0xeb3 + -0x2025) ? _0x3a3eb5(Object(_0xdb889d), !(-0x263c * 0x1 + 0x1 * -0xf7f + 0x7ad * 0x7))[_0x145ce6(0x254)](function (_0x328928) { _0x4a7824(_0xf371f0, _0x328928, _0xdb889d[_0x328928]) }) : Object[_0x145ce6(0x1ec)] ? Object[_0x145ce6(0x36c)](_0xf371f0, Object[_0x145ce6(0x1ec)](_0xdb889d)) : _0x3a3eb5(Object(_0xdb889d))[_0x145ce6(0x254)](function (_0x593f5f) { var _0x53f055 = _0x145ce6 Object[_0x53f055(0x175)](_0xf371f0, _0x593f5f, Object[_0x53f055(0x2a6)](_0xdb889d, _0x593f5f)) }) } return _0xf371f0 } function _0x385d19() { var _0x44a0fc = w_0x25f3 _0x385d19 = function () { return _0x507b23 } var _0x507b23 = {}, _0x39fa01 = Object[_0x44a0fc(0x344)], _0x43238c = _0x39fa01[_0x44a0fc(0x3b8)], _0x4cf7d8 = Object['defineProperty'] || function (_0x2541c5, _0x22c938, _0x405bab) { var _0x32f2ae = _0x44a0fc _0x2541c5[_0x22c938] = _0x405bab[_0x32f2ae(0x2e4)] }, _0x1c97cc = _0x44a0fc(0x1ee) == typeof Symbol ? Symbol : {}, _0x5acd1a = _0x1c97cc[_0x44a0fc(0x3b3)] || _0x44a0fc(0x1dd), _0x52f292 = _0x1c97cc['asyncIterator'] || _0x44a0fc(0x230), _0x447ab4 = _0x1c97cc[_0x44a0fc(0x1c0)] || _0x44a0fc(0x1e0) function _0x3baf2c(_0x30f952, _0x3ef614, _0x2d2b61) { var _0x598819 = _0x44a0fc return ( Object[_0x598819(0x175)](_0x30f952, _0x3ef614, { value: _0x2d2b61, enumerable: !(0x1b1a * -0x1 + 0x1 * 0x2696 + -0x31 * 0x3c), configurable: !(-0x1a13 + 0x5 * -0x6d + 0xa * 0x2d2), writable: !(-0x1cd + 0x214e + 0x1f81 * -0x1) }), _0x30f952[_0x3ef614] ) } try { _0x3baf2c({}, '') } catch (_0x275159) { _0x3baf2c = function (_0x37fa7b, _0x2671f0, _0x45b82e) { return (_0x37fa7b[_0x2671f0] = _0x45b82e) } } function _0x3e46c6(_0x50c0cc, _0x5f3c83, _0x148917, _0x2e5141) { var _0x1a25db = _0x44a0fc, _0x1b0fa0 = _0x5f3c83 && _0x5f3c83['prototype'] instanceof _0x50f36d ? _0x5f3c83 : _0x50f36d, _0x4f06ab = Object[_0x1a25db(0x3b7)](_0x1b0fa0[_0x1a25db(0x344)]), _0x3e4999 = new _0x1b5db9(_0x2e5141 || []) return ( _0x4cf7d8(_0x4f06ab, _0x1a25db(0x1b1), { value: _0x121728(_0x50c0cc, _0x148917, _0x3e4999) }), _0x4f06ab ) } function _0x575dfd(_0x48fd20, _0x6545ef, _0x242936) { var _0x580d50 = _0x44a0fc try { return { type: _0x580d50(0x2f1), arg: _0x48fd20[_0x580d50(0x334)](_0x6545ef, _0x242936) } } catch (_0x5aebac) { return { type: 'throw', arg: _0x5aebac } } } _0x507b23['wrap'] = _0x3e46c6 var _0x511b05 = {} function _0x50f36d() { } function _0x2e67e9() { } function _0x3a5ac7() { } var _0x4c3008 = {} _0x3baf2c(_0x4c3008, _0x5acd1a, function () { return this }) var _0x118945 = Object[_0x44a0fc(0x22c)], _0x5d1d04 = _0x118945 && _0x118945(_0x118945(_0x2edbf4([]))) _0x5d1d04 && _0x5d1d04 !== _0x39fa01 && _0x43238c[_0x44a0fc(0x334)](_0x5d1d04, _0x5acd1a) && (_0x4c3008 = _0x5d1d04) var _0x42763b = (_0x3a5ac7[_0x44a0fc(0x344)] = _0x50f36d['prototype'] = Object[_0x44a0fc(0x3b7)](_0x4c3008)) function _0x4e156b(_0x314ec0) { var _0x1229ff = _0x44a0fc ;[_0x1229ff(0x389), _0x1229ff(0x250), _0x1229ff(0x2fd)][_0x1229ff(0x254)](function (_0x1cac9a) { _0x3baf2c(_0x314ec0, _0x1cac9a, function (_0x509669) { var _0x3b5587 = w_0x25f3 return this[_0x3b5587(0x1b1)](_0x1cac9a, _0x509669) }) }) } function _0x23eb73(_0x5cb4f0, _0xfdda3) { var _0x2f70bc _0x4cf7d8(this, '_invoke', { value: function (_0x47f883, _0x34dd78) { var _0x5c5cca = w_0x25f3 function _0x65e836() { return new _0xfdda3(function (_0x494e99, _0x39f97a) { !(function _0x19e170(_0xd94afd, _0x7f5a3, _0x1fc978, _0x392c17) { var _0x5108db = w_0x25f3, _0x123c2b = _0x575dfd(_0x5cb4f0[_0xd94afd], _0x5cb4f0, _0x7f5a3) if (_0x5108db(0x250) !== _0x123c2b[_0x5108db(0x1ab)]) { var _0x57ff30 = _0x123c2b[_0x5108db(0x327)], _0x519f3c = _0x57ff30[_0x5108db(0x2e4)] return _0x519f3c && 'object' == typeof _0x519f3c && _0x43238c[_0x5108db(0x334)](_0x519f3c, _0x5108db(0x2b1)) ? _0xfdda3[_0x5108db(0x278)](_0x519f3c[_0x5108db(0x2b1)])[_0x5108db(0x1ed)]( function (_0x513ad4) { var _0x372e8b = _0x5108db _0x19e170(_0x372e8b(0x389), _0x513ad4, _0x1fc978, _0x392c17) }, function (_0x3ee973) { _0x19e170('throw', _0x3ee973, _0x1fc978, _0x392c17) } ) : _0xfdda3[_0x5108db(0x278)](_0x519f3c)[_0x5108db(0x1ed)]( function (_0xb8049c) { var _0x3f5791 = _0x5108db ; (_0x57ff30[_0x3f5791(0x2e4)] = _0xb8049c), _0x1fc978(_0x57ff30) }, function (_0x163a1d) { var _0x43e785 = _0x5108db return _0x19e170(_0x43e785(0x250), _0x163a1d, _0x1fc978, _0x392c17) } ) } _0x392c17(_0x123c2b[_0x5108db(0x327)]) })(_0x47f883, _0x34dd78, _0x494e99, _0x39f97a) }) } return (_0x2f70bc = _0x2f70bc ? _0x2f70bc[_0x5c5cca(0x1ed)](_0x65e836, _0x65e836) : _0x65e836()) } }) } function _0x121728(_0x39e85b, _0x26363f, _0x3838fc) { var _0x4a9454 = 'suspendedStart' return function (_0x33b907, _0x5c348b) { var _0x14af93 = w_0x25f3 if (_0x14af93(0x2ef) === _0x4a9454) throw new Error(_0x14af93(0x35a)) if ('completed' === _0x4a9454) { if ('throw' === _0x33b907) throw _0x5c348b return _0x159200() } for (_0x3838fc[_0x14af93(0x25a)] = _0x33b907, _0x3838fc[_0x14af93(0x327)] = _0x5c348b; ;) { var _0x43652a = _0x3838fc[_0x14af93(0x1bc)] if (_0x43652a) { var _0xc12f6f = _0x5489f3(_0x43652a, _0x3838fc) if (_0xc12f6f) { if (_0xc12f6f === _0x511b05) continue return _0xc12f6f } } if (_0x14af93(0x389) === _0x3838fc[_0x14af93(0x25a)]) _0x3838fc[_0x14af93(0x3b2)] = _0x3838fc[_0x14af93(0x2a2)] = _0x3838fc[_0x14af93(0x327)] else { if ('throw' === _0x3838fc[_0x14af93(0x25a)]) { if ('suspendedStart' === _0x4a9454) throw ((_0x4a9454 = _0x14af93(0x16a)), _0x3838fc['arg']) _0x3838fc[_0x14af93(0x2cb)](_0x3838fc[_0x14af93(0x327)]) } else _0x14af93(0x2fd) === _0x3838fc[_0x14af93(0x25a)] && _0x3838fc['abrupt'](_0x14af93(0x2fd), _0x3838fc['arg']) } _0x4a9454 = _0x14af93(0x2ef) var _0x1a99b5 = _0x575dfd(_0x39e85b, _0x26363f, _0x3838fc) if ('normal' === _0x1a99b5['type']) { if ( ((_0x4a9454 = _0x3838fc[_0x14af93(0x1e3)] ? _0x14af93(0x16a) : 'suspendedYield'), _0x1a99b5[_0x14af93(0x327)] === _0x511b05) ) continue return { value: _0x1a99b5[_0x14af93(0x327)], done: _0x3838fc[_0x14af93(0x1e3)] } } _0x14af93(0x250) === _0x1a99b5[_0x14af93(0x1ab)] && ((_0x4a9454 = _0x14af93(0x16a)), (_0x3838fc[_0x14af93(0x25a)] = _0x14af93(0x250)), (_0x3838fc[_0x14af93(0x327)] = _0x1a99b5[_0x14af93(0x327)])) } } } function _0x5489f3(_0x3c1e2d, _0x59877f) { var _0x299ed9 = _0x44a0fc, _0x1a45fc = _0x59877f['method'], _0x116edb = _0x3c1e2d[_0x299ed9(0x3b3)][_0x1a45fc] if (void (-0x15fe + 0xe93 + 0x76b) === _0x116edb) return ( (_0x59877f[_0x299ed9(0x1bc)] = null), (_0x299ed9(0x250) === _0x1a45fc && _0x3c1e2d[_0x299ed9(0x3b3)][_0x299ed9(0x2fd)] && ((_0x59877f['method'] = 'return'), (_0x59877f[_0x299ed9(0x327)] = void (-0x78 * -0x25 + -0x2272 + 0x111a * 0x1)), _0x5489f3(_0x3c1e2d, _0x59877f), _0x299ed9(0x250) === _0x59877f[_0x299ed9(0x25a)])) || ('return' !== _0x1a45fc && ((_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x250)), (_0x59877f[_0x299ed9(0x327)] = new TypeError( 'The\x20iterator\x20does\x20not\x20provide\x20a\x20\x27' + _0x1a45fc + _0x299ed9(0x32f) )))), _0x511b05 ) var _0x5be46a = _0x575dfd(_0x116edb, _0x3c1e2d[_0x299ed9(0x3b3)], _0x59877f[_0x299ed9(0x327)]) if (_0x299ed9(0x250) === _0x5be46a[_0x299ed9(0x1ab)]) return ( (_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x250)), (_0x59877f['arg'] = _0x5be46a[_0x299ed9(0x327)]), (_0x59877f[_0x299ed9(0x1bc)] = null), _0x511b05 ) var _0x44f533 = _0x5be46a[_0x299ed9(0x327)] return _0x44f533 ? _0x44f533['done'] ? ((_0x59877f[_0x3c1e2d[_0x299ed9(0x16e)]] = _0x44f533[_0x299ed9(0x2e4)]), (_0x59877f['next'] = _0x3c1e2d[_0x299ed9(0x281)]), _0x299ed9(0x2fd) !== _0x59877f[_0x299ed9(0x25a)] && ((_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x389)), (_0x59877f['arg'] = void (0x1a2 * -0x17 + -0x1910 + 0x5 * 0xc86))), (_0x59877f[_0x299ed9(0x1bc)] = null), _0x511b05) : _0x44f533 : ((_0x59877f[_0x299ed9(0x25a)] = _0x299ed9(0x250)), (_0x59877f['arg'] = new TypeError(_0x299ed9(0x251))), (_0x59877f[_0x299ed9(0x1bc)] = null), _0x511b05) } function _0x14015c(_0x5bad37) { var _0x42a847 = _0x44a0fc, _0x401cb9 = { tryLoc: _0x5bad37[-0x953 * 0x3 + 0xd3c + 0xebd] } ; -0x85b + 0x1181 + -0x925 in _0x5bad37 && (_0x401cb9['catchLoc'] = _0x5bad37[0x12b4 + -0x1d08 + 0xa55]), 0x4dc + 0x1b6f + 0xac3 * -0x3 in _0x5bad37 && ((_0x401cb9[_0x42a847(0x220)] = _0x5bad37[-0xd0c * -0x2 + 0x914 + -0xe * 0x283]), (_0x401cb9[_0x42a847(0x2fb)] = _0x5bad37[0x7 * -0x216 + 0x702 + 0x79b])), this['tryEntries'][_0x42a847(0x36e)](_0x401cb9) } function _0x2f82b3(_0x43fd78) { var _0x38de29 = _0x44a0fc, _0x2f1d6c = _0x43fd78[_0x38de29(0x387)] || {} ; (_0x2f1d6c['type'] = _0x38de29(0x2f1)), delete _0x2f1d6c[_0x38de29(0x327)], (_0x43fd78['completion'] = _0x2f1d6c) } function _0x1b5db9(_0x53b843) { var _0x2569b6 = _0x44a0fc ; (this[_0x2569b6(0x337)] = [ { tryLoc: _0x2569b6(0x1c3) } ]), _0x53b843[_0x2569b6(0x254)](_0x14015c, this), this[_0x2569b6(0x2aa)](!(0x1bba + 0x132e + -0x4c * 0x9e)) } function _0x2edbf4(_0xe32b16) { var _0x3a0ecf = _0x44a0fc if (_0xe32b16) { var _0x3f503a = _0xe32b16[_0x5acd1a] if (_0x3f503a) return _0x3f503a['call'](_0xe32b16) if (_0x3a0ecf(0x1ee) == typeof _0xe32b16[_0x3a0ecf(0x389)]) return _0xe32b16 if (!isNaN(_0xe32b16['length'])) { var _0x1ff1cf = -(-0x254c + 0xc7 * 0x11 + -0x2 * -0xc0b), _0x4f1000 = function _0x136bfc() { var _0x10b933 = _0x3a0ecf for (; ++_0x1ff1cf < _0xe32b16[_0x10b933(0x259)];) if (_0x43238c[_0x10b933(0x334)](_0xe32b16, _0x1ff1cf)) return ( (_0x136bfc[_0x10b933(0x2e4)] = _0xe32b16[_0x1ff1cf]), (_0x136bfc[_0x10b933(0x1e3)] = !(-0x1f79 + -0x22d2 + 0x424c)), _0x136bfc ) return ( (_0x136bfc['value'] = void (-0x639 + -0x115f + 0xa * 0x25c)), (_0x136bfc[_0x10b933(0x1e3)] = !(0x14ad + -0x1 * 0xa1b + -0xa92)), _0x136bfc ) } return (_0x4f1000[_0x3a0ecf(0x389)] = _0x4f1000) } } return { next: _0x159200 } } function _0x159200() { return { value: void (-0x540 + -0x12 * -0x60 + -0x8 * 0x30), done: !(-0x526 + -0x6d4 * 0x2 + -0x2 * -0x967) } } return ( (_0x2e67e9[_0x44a0fc(0x344)] = _0x3a5ac7), _0x4cf7d8(_0x42763b, _0x44a0fc(0x2ac), { value: _0x3a5ac7, configurable: !(-0x2414 + 0x1307 + 0x110d) }), _0x4cf7d8(_0x3a5ac7, _0x44a0fc(0x2ac), { value: _0x2e67e9, configurable: !(0x117d + -0x12aa + 0x12d) }), (_0x2e67e9[_0x44a0fc(0x18c)] = _0x3baf2c(_0x3a5ac7, _0x447ab4, _0x44a0fc(0x311))), (_0x507b23[_0x44a0fc(0x386)] = function (_0x54fdc6) { var _0x2c4038 = _0x44a0fc, _0x29797b = _0x2c4038(0x1ee) == typeof _0x54fdc6 && _0x54fdc6[_0x2c4038(0x2ac)] return !!_0x29797b && (_0x29797b === _0x2e67e9 || _0x2c4038(0x311) === (_0x29797b['displayName'] || _0x29797b['name'])) }), (_0x507b23[_0x44a0fc(0x3a5)] = function (_0x41ff3c) { var _0x286ce7 = _0x44a0fc return ( Object[_0x286ce7(0x23b)] ? Object[_0x286ce7(0x23b)](_0x41ff3c, _0x3a5ac7) : ((_0x41ff3c[_0x286ce7(0x2ea)] = _0x3a5ac7), _0x3baf2c(_0x41ff3c, _0x447ab4, 'GeneratorFunction')), (_0x41ff3c[_0x286ce7(0x344)] = Object['create'](_0x42763b)), _0x41ff3c ) }), (_0x507b23[_0x44a0fc(0x2d1)] = function (_0x4d3173) { return { __await: _0x4d3173 } }), _0x4e156b(_0x23eb73[_0x44a0fc(0x344)]), _0x3baf2c(_0x23eb73[_0x44a0fc(0x344)], _0x52f292, function () { return this }), (_0x507b23[_0x44a0fc(0x273)] = _0x23eb73), (_0x507b23[_0x44a0fc(0x1e7)] = function (_0x1403cf, _0xb864ce, _0x191461, _0x3aafb7, _0x4bc5ca) { var _0x225b19 = _0x44a0fc void (-0x1 * 0x1145 + -0x239 + -0x3e6 * -0x5) === _0x4bc5ca && (_0x4bc5ca = Promise) var _0x1e23c5 = new _0x23eb73(_0x3e46c6(_0x1403cf, _0xb864ce, _0x191461, _0x3aafb7), _0x4bc5ca) return _0x507b23[_0x225b19(0x386)](_0xb864ce) ? _0x1e23c5 : _0x1e23c5[_0x225b19(0x389)]()[_0x225b19(0x1ed)](function (_0x3bf8a0) { var _0x1af03c = _0x225b19 return _0x3bf8a0[_0x1af03c(0x1e3)] ? _0x3bf8a0[_0x1af03c(0x2e4)] : _0x1e23c5[_0x1af03c(0x389)]() }) }), _0x4e156b(_0x42763b), _0x3baf2c(_0x42763b, _0x447ab4, _0x44a0fc(0x1b5)), _0x3baf2c(_0x42763b, _0x5acd1a, function () { return this }), _0x3baf2c(_0x42763b, _0x44a0fc(0x3ae), function () { var _0x26f06c = _0x44a0fc return _0x26f06c(0x176) }), (_0x507b23['keys'] = function (_0x10e233) { var _0x515044 = _0x44a0fc, _0x184dfc = Object(_0x10e233), _0x1ee5ea = [] for (var _0x103175 in _0x184dfc) _0x1ee5ea[_0x515044(0x36e)](_0x103175) return ( _0x1ee5ea[_0x515044(0x2f3)](), function _0x5c4b0b() { var _0x4f9a2b = _0x515044 for (; _0x1ee5ea[_0x4f9a2b(0x259)];) { var _0x180e64 = _0x1ee5ea[_0x4f9a2b(0x267)]() if (_0x180e64 in _0x184dfc) return ( (_0x5c4b0b[_0x4f9a2b(0x2e4)] = _0x180e64), (_0x5c4b0b[_0x4f9a2b(0x1e3)] = !(0x411 * -0x2 + -0x20 * 0x3c + 0x1 * 0xfa3)), _0x5c4b0b ) } return (_0x5c4b0b['done'] = !(-0x4d2 * -0x5 + -0x3fd + -0x13 * 0x10f)), _0x5c4b0b } ) }), (_0x507b23[_0x44a0fc(0x38b)] = _0x2edbf4), (_0x1b5db9['prototype'] = { constructor: _0x1b5db9, reset: function (_0x3ebc58) { var _0x52c025 = _0x44a0fc if ( ((this[_0x52c025(0x32c)] = -0x16 * 0x181 + 0x1e6a + 0x2ac), (this[_0x52c025(0x389)] = 0x1 * 0xa3f + -0x1 * 0x1fb7 + 0x1578), (this[_0x52c025(0x3b2)] = this[_0x52c025(0x2a2)] = void (0x18ca + -0x52c * 0x2 + -0xe72)), (this[_0x52c025(0x1e3)] = !(-0x775 + -0xfe1 + -0x1757 * -0x1)), (this[_0x52c025(0x1bc)] = null), (this[_0x52c025(0x25a)] = _0x52c025(0x389)), (this[_0x52c025(0x327)] = void (-0x1a0a + -0x263c + -0x2 * -0x2023)), this[_0x52c025(0x337)][_0x52c025(0x254)](_0x2f82b3), !_0x3ebc58) ) { for (var _0x271134 in this) 't' === _0x271134['charAt'](0x3 * 0x707 + 0x2132 + 0x7 * -0x7c1) && _0x43238c[_0x52c025(0x334)](this, _0x271134) && !isNaN(+_0x271134['slice'](0x2629 * 0x1 + -0x7ec + -0x1e3c)) && (this[_0x271134] = void (0x14a3 + 0x211 + -0x16b4)) } }, stop: function () { var _0x5d1331 = _0x44a0fc this[_0x5d1331(0x1e3)] = !(-0x1157 + -0x1d00 * -0x1 + -0xba9) var _0x360ca1 = this[_0x5d1331(0x337)][0x181c + 0x2252 + 0x137a * -0x3][_0x5d1331(0x387)] if (_0x5d1331(0x250) === _0x360ca1[_0x5d1331(0x1ab)]) throw _0x360ca1['arg'] return this[_0x5d1331(0x29a)] }, dispatchException: function (_0x5ccdbe) { var _0x2739ee = _0x44a0fc if (this[_0x2739ee(0x1e3)]) throw _0x5ccdbe var _0x2375b1 = this function _0x5bc3f7(_0x2f8813, _0x2926a6) { var _0x19cf66 = _0x2739ee return ( (_0x459dde[_0x19cf66(0x1ab)] = _0x19cf66(0x250)), (_0x459dde[_0x19cf66(0x327)] = _0x5ccdbe), (_0x2375b1[_0x19cf66(0x389)] = _0x2f8813), _0x2926a6 && ((_0x2375b1[_0x19cf66(0x25a)] = _0x19cf66(0x389)), (_0x2375b1[_0x19cf66(0x327)] = void (-0x77f + -0x1c03 * -0x1 + -0xd * 0x194))), !!_0x2926a6 ) } for ( var _0x218123 = this[_0x2739ee(0x337)][_0x2739ee(0x259)] - (-0x8ed + -0x9e5 + 0x12d3); _0x218123 >= -0x3 * -0x4ef + -0x161b * -0x1 + -0x24e8; --_0x218123 ) { var _0x5e4d00 = this[_0x2739ee(0x337)][_0x218123], _0x459dde = _0x5e4d00[_0x2739ee(0x387)] if (_0x2739ee(0x1c3) === _0x5e4d00['tryLoc']) return _0x5bc3f7(_0x2739ee(0x1db)) if (_0x5e4d00[_0x2739ee(0x29e)] <= this[_0x2739ee(0x32c)]) { var _0x55fd7f = _0x43238c['call'](_0x5e4d00, 'catchLoc'), _0x47cf6c = _0x43238c[_0x2739ee(0x334)](_0x5e4d00, _0x2739ee(0x220)) if (_0x55fd7f && _0x47cf6c) { if (this[_0x2739ee(0x32c)] < _0x5e4d00[_0x2739ee(0x2c4)]) return _0x5bc3f7(_0x5e4d00['catchLoc'], !(-0x25 * 0xe9 + -0x2368 + 0x4515)) if (this['prev'] < _0x5e4d00[_0x2739ee(0x220)]) return _0x5bc3f7(_0x5e4d00[_0x2739ee(0x220)]) } else { if (_0x55fd7f) { if (this['prev'] < _0x5e4d00[_0x2739ee(0x2c4)]) return _0x5bc3f7(_0x5e4d00[_0x2739ee(0x2c4)], !(0xf11 + -0x1032 + -0x121 * -0x1)) } else { if (!_0x47cf6c) throw new Error(_0x2739ee(0x33e)) if (this[_0x2739ee(0x32c)] < _0x5e4d00['finallyLoc']) return _0x5bc3f7(_0x5e4d00['finallyLoc']) } } } } }, abrupt: function (_0x452b06, _0x46591d) { var _0x189350 = _0x44a0fc for ( var _0x24d9ee = this[_0x189350(0x337)][_0x189350(0x259)] - (-0x1 * -0x434 + 0xb2d * -0x1 + 0x6fa); _0x24d9ee >= 0x144c + -0x1 * 0x80f + -0xc3d; --_0x24d9ee ) { var _0x3e29ca = this[_0x189350(0x337)][_0x24d9ee] if ( _0x3e29ca[_0x189350(0x29e)] <= this[_0x189350(0x32c)] && _0x43238c[_0x189350(0x334)](_0x3e29ca, _0x189350(0x220)) && this[_0x189350(0x32c)] < _0x3e29ca[_0x189350(0x220)] ) { var _0x35a2dc = _0x3e29ca break } } _0x35a2dc && (_0x189350(0x31f) === _0x452b06 || _0x189350(0x2d2) === _0x452b06) && _0x35a2dc[_0x189350(0x29e)] <= _0x46591d && _0x46591d <= _0x35a2dc[_0x189350(0x220)] && (_0x35a2dc = null) var _0x1837c0 = _0x35a2dc ? _0x35a2dc[_0x189350(0x387)] : {} return ( (_0x1837c0['type'] = _0x452b06), (_0x1837c0[_0x189350(0x327)] = _0x46591d), _0x35a2dc ? ((this[_0x189350(0x25a)] = _0x189350(0x389)), (this[_0x189350(0x389)] = _0x35a2dc[_0x189350(0x220)]), _0x511b05) : this[_0x189350(0x162)](_0x1837c0) ) }, complete: function (_0x4daef1, _0x152d13) { var _0x2e0c88 = _0x44a0fc if (_0x2e0c88(0x250) === _0x4daef1[_0x2e0c88(0x1ab)]) throw _0x4daef1[_0x2e0c88(0x327)] return ( _0x2e0c88(0x31f) === _0x4daef1[_0x2e0c88(0x1ab)] || _0x2e0c88(0x2d2) === _0x4daef1[_0x2e0c88(0x1ab)] ? (this[_0x2e0c88(0x389)] = _0x4daef1[_0x2e0c88(0x327)]) : _0x2e0c88(0x2fd) === _0x4daef1['type'] ? ((this[_0x2e0c88(0x29a)] = this[_0x2e0c88(0x327)] = _0x4daef1[_0x2e0c88(0x327)]), (this[_0x2e0c88(0x25a)] = _0x2e0c88(0x2fd)), (this[_0x2e0c88(0x389)] = 'end')) : _0x2e0c88(0x2f1) === _0x4daef1[_0x2e0c88(0x1ab)] && _0x152d13 && (this[_0x2e0c88(0x389)] = _0x152d13), _0x511b05 ) }, finish: function (_0x33d396) { var _0x38fc51 = _0x44a0fc for ( var _0x5abbd8 = this[_0x38fc51(0x337)][_0x38fc51(0x259)] - (0x1b6c + 0x10f1 + -0x2c5c); _0x5abbd8 >= -0x106c + -0x26aa + 0x3716; --_0x5abbd8 ) { var _0x5eb5c4 = this[_0x38fc51(0x337)][_0x5abbd8] if (_0x5eb5c4[_0x38fc51(0x220)] === _0x33d396) return this['complete'](_0x5eb5c4[_0x38fc51(0x387)], _0x5eb5c4[_0x38fc51(0x2fb)]), _0x2f82b3(_0x5eb5c4), _0x511b05 } }, catch: function (_0x235ccf) { var _0x4e3345 = _0x44a0fc for ( var _0x1db840 = this['tryEntries'][_0x4e3345(0x259)] - (-0x3a * -0x4f + -0x1 * -0x12d6 + -0x24bb * 0x1); _0x1db840 >= -0x168 + 0x305 + -0x19d; --_0x1db840 ) { var _0x545b66 = this['tryEntries'][_0x1db840] if (_0x545b66[_0x4e3345(0x29e)] === _0x235ccf) { var _0x2d5b63 = _0x545b66[_0x4e3345(0x387)] if (_0x4e3345(0x250) === _0x2d5b63[_0x4e3345(0x1ab)]) { var _0x13e035 = _0x2d5b63[_0x4e3345(0x327)] _0x2f82b3(_0x545b66) } return _0x13e035 } } throw new Error(_0x4e3345(0x23f)) }, delegateYield: function (_0x395df9, _0x50d973, _0x48faf1) { var _0x39919e = _0x44a0fc return ( (this[_0x39919e(0x1bc)] = { iterator: _0x2edbf4(_0x395df9), resultName: _0x50d973, nextLoc: _0x48faf1 }), 'next' === this['method'] && (this['arg'] = void (0x1958 + -0xaba + -0xe9e)), _0x511b05 ) } }), _0x507b23 ) } function _0x1db123(_0x149c27) { var _0x39d672 = w_0x25f3 return (_0x1db123 = _0x39d672(0x1ee) == typeof Symbol && 'symbol' == typeof Symbol['iterator'] ? function (_0x4a8f2c) { return typeof _0x4a8f2c } : function (_0x40eb64) { var _0x4f8eee = _0x39d672 return _0x40eb64 && _0x4f8eee(0x1ee) == typeof Symbol && _0x40eb64[_0x4f8eee(0x2ac)] === Symbol && _0x40eb64 !== Symbol['prototype'] ? _0x4f8eee(0x2ed) : typeof _0x40eb64 })(_0x149c27) } function _0x34d29a() { var _0x4bbdba = w_0x25f3 _0x34d29a = function (_0x1859fe, _0x26adf2) { return new _0x3b92d4(_0x1859fe, void (-0x1f * 0x133 + 0x3 * 0x4f5 + 0x23b * 0xa), _0x26adf2) } var _0x5aed6e = RegExp[_0x4bbdba(0x344)], _0x58ba91 = new WeakMap() function _0x3b92d4(_0x2f61fd, _0x513c44, _0xaf22fc) { var _0xd932c6 = _0x4bbdba, _0xd60509 = new RegExp(_0x2f61fd, _0x513c44) return ( _0x58ba91[_0xd932c6(0x1e4)](_0xd60509, _0xaf22fc || _0x58ba91[_0xd932c6(0x32b)](_0x2f61fd)), _0x2e2f47(_0xd60509, _0x3b92d4[_0xd932c6(0x344)]) ) } function _0x427d42(_0x489eeb, _0x1699d8) { var _0x1004fb = _0x4bbdba, _0x2ae826 = _0x58ba91[_0x1004fb(0x32b)](_0x1699d8) return Object[_0x1004fb(0x17f)](_0x2ae826)[_0x1004fb(0x376)](function (_0x100f10, _0x5bfdf5) { var _0x3ad421 = _0x1004fb, _0x541568 = _0x2ae826[_0x5bfdf5] if (_0x3ad421(0x28b) == typeof _0x541568) _0x100f10[_0x5bfdf5] = _0x489eeb[_0x541568] else { for ( var _0x3bc728 = 0x1 * 0x3ce + 0x3 * -0x435 + 0x8d1; void (0x2695 + 0x1ee8 + -0x457d) === _0x489eeb[_0x541568[_0x3bc728]] && _0x3bc728 + (0x3fb * -0x2 + 0x2631 + -0x2 * 0xf1d) < _0x541568['length']; ) _0x3bc728++ _0x100f10[_0x5bfdf5] = _0x489eeb[_0x541568[_0x3bc728]] } return _0x100f10 }, Object[_0x1004fb(0x3b7)](null)) } return ( _0x5dda7d(_0x3b92d4, RegExp), (_0x3b92d4['prototype']['exec'] = function (_0x1bc796) { var _0x2a6afd = _0x4bbdba, _0x457628 = _0x5aed6e[_0x2a6afd(0x209)]['call'](this, _0x1bc796) if (_0x457628) { _0x457628['groups'] = _0x427d42(_0x457628, this) var _0x546542 = _0x457628['indices'] _0x546542 && (_0x546542['groups'] = _0x427d42(_0x546542, this)) } return _0x457628 }), (_0x3b92d4[_0x4bbdba(0x344)][Symbol[_0x4bbdba(0x377)]] = function (_0x10e2ef, _0x453a26) { var _0x226516 = _0x4bbdba if (_0x226516(0x33c) == typeof _0x453a26) { var _0x42705a = _0x58ba91[_0x226516(0x32b)](this) return _0x5aed6e[Symbol[_0x226516(0x377)]]['call']( this, _0x10e2ef, _0x453a26[_0x226516(0x377)](/\$<([^>]+)>/g, function (_0x4536fa, _0x53b1c5) { var _0x5db08d = _0x226516, _0x1b4f5c = _0x42705a[_0x53b1c5] return '$' + (Array[_0x5db08d(0x2af)](_0x1b4f5c) ? _0x1b4f5c[_0x5db08d(0x24f)]('$') : _0x1b4f5c) }) ) } if (_0x226516(0x1ee) == typeof _0x453a26) { var _0x51880e = this return _0x5aed6e[Symbol[_0x226516(0x377)]][_0x226516(0x334)](this, _0x10e2ef, function () { var _0x3ce548 = _0x226516, _0x352e21 = arguments return ( _0x3ce548(0x17d) != typeof _0x352e21[_0x352e21[_0x3ce548(0x259)] - (-0xf9 * -0x7 + 0xd4 + -0x2 * 0x3d1)] && (_0x352e21 = []['slice'][_0x3ce548(0x334)](_0x352e21))[_0x3ce548(0x36e)](_0x427d42(_0x352e21, _0x51880e)), _0x453a26[_0x3ce548(0x207)](this, _0x352e21) ) }) } return _0x5aed6e[Symbol[_0x226516(0x377)]]['call'](this, _0x10e2ef, _0x453a26) }), _0x34d29a[_0x4bbdba(0x207)](this, arguments) ) } function _0x2772ab(_0x17b93c) { var _0x2e8af4 = w_0x25f3 this[_0x2e8af4(0x180)] = _0x17b93c } function _0x125e01(_0x221f1a) { return function () { var _0x2db496 = w_0x25f3 return new _0x137ba2(_0x221f1a[_0x2db496(0x207)](this, arguments)) } } function _0x8a0370(_0x1ac7e2, _0x440b38, _0x4611ac, _0x1f79f3, _0x26eb95, _0x4af1d4, _0x2b24bc) { var _0x3a480e = w_0x25f3 try { var _0x16d0ce = _0x1ac7e2[_0x4af1d4](_0x2b24bc), _0x2e8eaf = _0x16d0ce[_0x3a480e(0x2e4)] } catch (_0xc88fae) { return void _0x4611ac(_0xc88fae) } _0x16d0ce[_0x3a480e(0x1e3)] ? _0x440b38(_0x2e8eaf) : Promise[_0x3a480e(0x278)](_0x2e8eaf)[_0x3a480e(0x1ed)](_0x1f79f3, _0x26eb95) } function _0x50daaa(_0x10de0d) { return function () { var _0x310206 = this, _0x17ad73 = arguments return new Promise(function (_0x37120b, _0x728e37) { var _0x5a819e = _0x10de0d['apply'](_0x310206, _0x17ad73) function _0x12466a(_0x263e68) { var _0x123e7f = w_0x25f3 _0x8a0370(_0x5a819e, _0x37120b, _0x728e37, _0x12466a, _0x191f8b, _0x123e7f(0x389), _0x263e68) } function _0x191f8b(_0x255ae1) { var _0x5d15ce = w_0x25f3 _0x8a0370(_0x5a819e, _0x37120b, _0x728e37, _0x12466a, _0x191f8b, _0x5d15ce(0x250), _0x255ae1) } _0x12466a(void (0xbdf + -0x129c + -0x19 * -0x45)) }) } } function _0x297d3d(_0xd86983, _0x45590a) { var _0x51c357 = w_0x25f3 if (!(_0xd86983 instanceof _0x45590a)) throw new TypeError(_0x51c357(0x2f7)) } function _0x96f358(_0x217e4a, _0x156410) { var _0x251198 = w_0x25f3 for (var _0x336960 = 0x1613 + -0x2f * 0x3b + 0xb3e * -0x1; _0x336960 < _0x156410[_0x251198(0x259)]; _0x336960++) { var _0x3d27f0 = _0x156410[_0x336960] ; (_0x3d27f0[_0x251198(0x23a)] = _0x3d27f0[_0x251198(0x23a)] || !(-0xbf7 + -0x166e + 0x2266)), (_0x3d27f0[_0x251198(0x2bc)] = !(-0xde + 0x1c94 + -0x1bb6)), _0x251198(0x2e4) in _0x3d27f0 && (_0x3d27f0['writable'] = !(-0x21 * 0x12f + -0x2 * -0x17d + 0x2415)), Object[_0x251198(0x175)](_0x217e4a, _0x32e885(_0x3d27f0[_0x251198(0x392)]), _0x3d27f0) } } function _0x55cd8a(_0x174a54, _0x5e25eb, _0x465e50) { var _0x4d17e4 = w_0x25f3 return ( _0x5e25eb && _0x96f358(_0x174a54[_0x4d17e4(0x344)], _0x5e25eb), _0x465e50 && _0x96f358(_0x174a54, _0x465e50), Object[_0x4d17e4(0x175)](_0x174a54, _0x4d17e4(0x344), { writable: !(-0xc19 + 0x1aa + -0x2 * -0x538) }), _0x174a54 ) } function _0x58d8c2(_0x5634d7, _0x53515c) { var _0x5fc7bf = w_0x25f3 for (var _0x5e7563 in _0x53515c) { ; ((_0x532356 = _0x53515c[_0x5e7563])[_0x5fc7bf(0x2bc)] = _0x532356[_0x5fc7bf(0x23a)] = !(0xb5 + 0x6 * 0x80 + -0x3b5)), 'value' in _0x532356 && (_0x532356[_0x5fc7bf(0x2e3)] = !(0x19d * 0x11 + 0x126f + -0x2ddc)), Object[_0x5fc7bf(0x175)](_0x5634d7, _0x5e7563, _0x532356) } if (Object[_0x5fc7bf(0x388)]) for ( var _0x45bcc1 = Object[_0x5fc7bf(0x388)](_0x53515c), _0x368698 = -0x11 * -0x1af + -0x1ec7 + 0x228; _0x368698 < _0x45bcc1[_0x5fc7bf(0x259)]; _0x368698++ ) { var _0x532356, _0x6be33e = _0x45bcc1[_0x368698] ; ((_0x532356 = _0x53515c[_0x6be33e])['configurable'] = _0x532356[_0x5fc7bf(0x23a)] = !(-0x833 + 0x9 * -0x76 + 0x1d * 0x6d)), _0x5fc7bf(0x2e4) in _0x532356 && (_0x532356[_0x5fc7bf(0x2e3)] = !(0x18bf + -0x337 * 0x5 + -0x14 * 0x6f)), Object[_0x5fc7bf(0x175)](_0x5634d7, _0x6be33e, _0x532356) } return _0x5634d7 } function _0x40ff51(_0x254aaa, _0x287254) { var _0x77273f = w_0x25f3 for ( var _0x587d0b = Object[_0x77273f(0x32a)](_0x287254), _0xa5f40d = -0x2174 + 0x25a * -0x2 + 0x42 * 0x94; _0xa5f40d < _0x587d0b[_0x77273f(0x259)]; _0xa5f40d++ ) { var _0x23b426 = _0x587d0b[_0xa5f40d], _0x59ae3e = Object[_0x77273f(0x2a6)](_0x287254, _0x23b426) _0x59ae3e && _0x59ae3e[_0x77273f(0x2bc)] && void (-0x221b * 0x1 + 0x2326 * 0x1 + -0x10b) === _0x254aaa[_0x23b426] && Object['defineProperty'](_0x254aaa, _0x23b426, _0x59ae3e) } return _0x254aaa } function _0x4a7824(_0x26784f, _0x47795a, _0x26a673) { var _0x1edba1 = w_0x25f3 return ( (_0x47795a = _0x32e885(_0x47795a)) in _0x26784f ? Object[_0x1edba1(0x175)](_0x26784f, _0x47795a, { value: _0x26a673, enumerable: !(0x24eb + 0x1b2 + -0x1 * 0x269d), configurable: !(-0x472 + -0xb7 * 0x12 + 0x1150), writable: !(-0x23f8 + 0x257d + -0x185 * 0x1) }) : (_0x26784f[_0x47795a] = _0x26a673), _0x26784f ) } function _0x36f54f() { var _0x472dbc = w_0x25f3 return (_0x36f54f = Object['assign'] ? Object[_0x472dbc(0x2a0)]['bind']() : function (_0x3e0b52) { var _0x1eddf8 = _0x472dbc for (var _0x16d75e = -0x645 + -0x2115 * 0x1 + -0x19 * -0x193; _0x16d75e < arguments[_0x1eddf8(0x259)]; _0x16d75e++) { var _0x5a9173 = arguments[_0x16d75e] for (var _0x145ff6 in _0x5a9173) Object[_0x1eddf8(0x344)][_0x1eddf8(0x3b8)][_0x1eddf8(0x334)](_0x5a9173, _0x145ff6) && (_0x3e0b52[_0x145ff6] = _0x5a9173[_0x145ff6]) } return _0x3e0b52 })['apply'](this, arguments) } function _0x5f346f(_0x2ab8ef) { var _0x39ff04 = w_0x25f3 for (var _0x176101 = 0xc60 + -0x43 * -0x1f + 0x6 * -0x36a; _0x176101 < arguments[_0x39ff04(0x259)]; _0x176101++) { var _0x99688c = null != arguments[_0x176101] ? Object(arguments[_0x176101]) : {}, _0xbf3314 = Object[_0x39ff04(0x17f)](_0x99688c) _0x39ff04(0x1ee) == typeof Object[_0x39ff04(0x388)] && _0xbf3314[_0x39ff04(0x36e)][_0x39ff04(0x207)]( _0xbf3314, Object[_0x39ff04(0x388)](_0x99688c)[_0x39ff04(0x164)](function (_0x2adc39) { var _0x23e48e = _0x39ff04 return Object[_0x23e48e(0x2a6)](_0x99688c, _0x2adc39)[_0x23e48e(0x23a)] }) ), _0xbf3314['forEach'](function (_0x2e44e4) { _0x4a7824(_0x2ab8ef, _0x2e44e4, _0x99688c[_0x2e44e4]) }) } return _0x2ab8ef } function _0x5dda7d(_0x46427b, _0x4b68de) { var _0x5c7f41 = w_0x25f3 if ('function' != typeof _0x4b68de && null !== _0x4b68de) throw new TypeError(_0x5c7f41(0x236)) ; (_0x46427b[_0x5c7f41(0x344)] = Object['create'](_0x4b68de && _0x4b68de[_0x5c7f41(0x344)], { constructor: { value: _0x46427b, writable: !(-0x59 * -0x6d + -0x3a5 + -0x2240), configurable: !(0xf4d * -0x2 + -0x182e + 0x1b64 * 0x2) } })), Object[_0x5c7f41(0x175)](_0x46427b, _0x5c7f41(0x344), { writable: !(-0x9d0 * -0x1 + 0x17a1 + -0x217 * 0x10) }), _0x4b68de && _0x2e2f47(_0x46427b, _0x4b68de) } function _0x3879ac(_0x40738f, _0x3ddb1f) { var _0x34aaee = w_0x25f3 ; (_0x40738f[_0x34aaee(0x344)] = Object['create'](_0x3ddb1f[_0x34aaee(0x344)])), (_0x40738f[_0x34aaee(0x344)][_0x34aaee(0x2ac)] = _0x40738f), _0x2e2f47(_0x40738f, _0x3ddb1f) } function _0x22af63(_0x26c4e4) { var _0x3c9cd2 = w_0x25f3 return (_0x22af63 = Object[_0x3c9cd2(0x23b)] ? Object['getPrototypeOf'][_0x3c9cd2(0x301)]() : function (_0x212968) { var _0x3a939f = _0x3c9cd2 return _0x212968['__proto__'] || Object[_0x3a939f(0x22c)](_0x212968) })(_0x26c4e4) } function _0x2e2f47(_0x24c757, _0x1d9d80) { var _0x5e1251 = w_0x25f3 return (_0x2e2f47 = Object['setPrototypeOf'] ? Object[_0x5e1251(0x23b)][_0x5e1251(0x301)]() : function (_0x1f13b4, _0x24fdc8) { var _0x16bc1b = _0x5e1251 return (_0x1f13b4[_0x16bc1b(0x2ea)] = _0x24fdc8), _0x1f13b4 })(_0x24c757, _0x1d9d80) } function _0x3390dc() { var _0x31b3f3 = w_0x25f3 if (_0x31b3f3(0x384) == typeof Reflect || !Reflect[_0x31b3f3(0x320)]) return !(-0x1158 + -0x789 + 0x18e2) if (Reflect[_0x31b3f3(0x320)]['sham']) return !(0xec5 + 0x8 * -0x92 + -0xa34 * 0x1) if (_0x31b3f3(0x1ee) == typeof Proxy) return !(-0xe01 + 0xa7b + 0x386) try { return ( Boolean[_0x31b3f3(0x344)][_0x31b3f3(0x303)][_0x31b3f3(0x334)](Reflect[_0x31b3f3(0x320)](Boolean, [], function () { })), !(-0xe0c + -0x2415 + 0x3221 * 0x1) ) } catch (_0x20aa1e) { return !(0xd * -0xa4 + -0xc1f + 0x1474) } } function _0x920a3d(_0x35e7ab, _0x5cbd00, _0x53ced5) { var _0x4ba719 = w_0x25f3 return (_0x920a3d = _0x3390dc() ? Reflect['construct'][_0x4ba719(0x301)]() : function (_0x40c7ae, _0xd26edf, _0x5ecdaf) { var _0x3b4c0f = _0x4ba719, _0x55cb1f = [null] _0x55cb1f['push'][_0x3b4c0f(0x207)](_0x55cb1f, _0xd26edf) var _0x47f6fb = new (Function[_0x3b4c0f(0x301)]['apply'](_0x40c7ae, _0x55cb1f))() return _0x5ecdaf && _0x2e2f47(_0x47f6fb, _0x5ecdaf[_0x3b4c0f(0x344)]), _0x47f6fb })['apply'](null, arguments) } function _0x5cb0d7(_0x6e2f2f) { var _0x26e451 = w_0x25f3 return -(-0x65 * 0x35 + -0x2087 + -0x3571 * -0x1) !== Function[_0x26e451(0x3ae)]['call'](_0x6e2f2f)[_0x26e451(0x2c5)](_0x26e451(0x161)) } function _0x16f283(_0x11646e) { var _0x9334eb = w_0x25f3, _0x551d10 = _0x9334eb(0x1ee) == typeof Map ? new Map() : void (-0xe * -0x5 + 0xd * -0x151 + 0x3 * 0x59d) return (_0x16f283 = function (_0xffb48b) { var _0x30c56b = _0x9334eb if (null === _0xffb48b || !_0x5cb0d7(_0xffb48b)) return _0xffb48b if (_0x30c56b(0x1ee) != typeof _0xffb48b) throw new TypeError(_0x30c56b(0x236)) if (void (0x12 * 0xf8 + -0x41b + 0xd55 * -0x1) !== _0x551d10) { if (_0x551d10[_0x30c56b(0x2fc)](_0xffb48b)) return _0x551d10[_0x30c56b(0x32b)](_0xffb48b) _0x551d10[_0x30c56b(0x1e4)](_0xffb48b, _0xfee014) } function _0xfee014() { var _0x10fec4 = _0x30c56b return _0x920a3d(_0xffb48b, arguments, _0x22af63(this)[_0x10fec4(0x2ac)]) } return ( (_0xfee014['prototype'] = Object[_0x30c56b(0x3b7)](_0xffb48b[_0x30c56b(0x344)], { constructor: { value: _0xfee014, enumerable: !(0x829 + 0x1 * -0x1271 + 0xa49), writable: !(0x724 + 0x15f9 + 0x1d * -0x101), configurable: !(0x3e4 + 0x685 * 0x4 + 0x1df8 * -0x1) } })), _0x2e2f47(_0xfee014, _0xffb48b) ) })(_0x11646e) } function _0x8f6e33(_0xca4201, _0x572889) { var _0x44fa42 = w_0x25f3 return null != _0x572889 && _0x44fa42(0x384) != typeof Symbol && _0x572889[Symbol[_0x44fa42(0x178)]] ? !!_0x572889[Symbol[_0x44fa42(0x178)]](_0xca4201) : _0xca4201 instanceof _0x572889 } function _0x2ea366(_0x4da731) { var _0x2c9369 = w_0x25f3 return _0x4da731 && _0x4da731[_0x2c9369(0x3bd)] ? _0x4da731 : { default: _0x4da731 } } function _0x1629e6(_0xb8ec58) { var _0xd6f6f1 = w_0x25f3 if (_0xd6f6f1(0x1ee) != typeof WeakMap) return null var _0x2d8f39 = new WeakMap(), _0x2398fe = new WeakMap() return (_0x1629e6 = function (_0x164b35) { return _0x164b35 ? _0x2398fe : _0x2d8f39 })(_0xb8ec58) } function _0x2c9158(_0x2f5c3e, _0x55c9ff) { var _0x3d4018 = w_0x25f3 if (!_0x55c9ff && _0x2f5c3e && _0x2f5c3e['__esModule']) return _0x2f5c3e if (null === _0x2f5c3e || (_0x3d4018(0x17d) != typeof _0x2f5c3e && 'function' != typeof _0x2f5c3e)) return { default: _0x2f5c3e } var _0xcafe97 = _0x1629e6(_0x55c9ff) if (_0xcafe97 && _0xcafe97[_0x3d4018(0x2fc)](_0x2f5c3e)) return _0xcafe97[_0x3d4018(0x32b)](_0x2f5c3e) var _0x41e330 = {}, _0x115c7f = Object[_0x3d4018(0x175)] && Object[_0x3d4018(0x2a6)] for (var _0x84a510 in _0x2f5c3e) if (_0x3d4018(0x1d3) !== _0x84a510 && Object[_0x3d4018(0x344)]['hasOwnProperty'][_0x3d4018(0x334)](_0x2f5c3e, _0x84a510)) { var _0x422bcd = _0x115c7f ? Object[_0x3d4018(0x2a6)](_0x2f5c3e, _0x84a510) : null _0x422bcd && (_0x422bcd[_0x3d4018(0x32b)] || _0x422bcd[_0x3d4018(0x1e4)]) ? Object['defineProperty'](_0x41e330, _0x84a510, _0x422bcd) : (_0x41e330[_0x84a510] = _0x2f5c3e[_0x84a510]) } return (_0x41e330['default'] = _0x2f5c3e), _0xcafe97 && _0xcafe97[_0x3d4018(0x1e4)](_0x2f5c3e, _0x41e330), _0x41e330 } function _0x374736(_0x2d130b, _0x324593) { var _0x4ccff2 = w_0x25f3 if (_0x2d130b !== _0x324593) throw new TypeError(_0x4ccff2(0x16c)) } function _0x206199(_0x607e62) { var _0x5bbb21 = w_0x25f3 if (null == _0x607e62) throw new TypeError(_0x5bbb21(0x1cc) + _0x607e62) } function _0x2bfa3e(_0x161463, _0x2ff4d5) { var _0x59d7ee = w_0x25f3 if (null == _0x161463) return {} var _0x31fbf6, _0x50d0b6, _0x5ca1c5 = {}, _0x5b71fd = Object['keys'](_0x161463) for (_0x50d0b6 = -0x763 + -0x15a + 0x1 * 0x8bd; _0x50d0b6 < _0x5b71fd[_0x59d7ee(0x259)]; _0x50d0b6++) (_0x31fbf6 = _0x5b71fd[_0x50d0b6]), _0x2ff4d5[_0x59d7ee(0x2c5)](_0x31fbf6) >= 0x8a7 + -0x21ed + 0x1946 || (_0x5ca1c5[_0x31fbf6] = _0x161463[_0x31fbf6]) return _0x5ca1c5 } function _0x2a28e9(_0x2cdf2e, _0x74ac11) { var _0x942c51 = w_0x25f3 if (null == _0x2cdf2e) return {} var _0x5ef46e, _0x5acf70, _0x282df4 = _0x2bfa3e(_0x2cdf2e, _0x74ac11) if (Object['getOwnPropertySymbols']) { var _0x33d708 = Object[_0x942c51(0x388)](_0x2cdf2e) for (_0x5acf70 = -0xd30 + 0x4a1 * 0x1 + 0x7 * 0x139; _0x5acf70 < _0x33d708[_0x942c51(0x259)]; _0x5acf70++) (_0x5ef46e = _0x33d708[_0x5acf70]), _0x74ac11[_0x942c51(0x2c5)](_0x5ef46e) >= -0x1f5d * 0x1 + 0x40b + 0x1b52 || (Object[_0x942c51(0x344)][_0x942c51(0x1da)][_0x942c51(0x334)](_0x2cdf2e, _0x5ef46e) && (_0x282df4[_0x5ef46e] = _0x2cdf2e[_0x5ef46e])) } return _0x282df4 } function _0x58f550(_0x94e938) { var _0x41d076 = w_0x25f3 if (void (-0x6a * 0x1 + -0xf6 + 0x160) === _0x94e938) throw new ReferenceError(_0x41d076(0x1bb)) return _0x94e938 } function _0xf3b17(_0x7b2cf6, _0x347c9f) { var _0x41f350 = w_0x25f3 if (_0x347c9f && (_0x41f350(0x17d) == typeof _0x347c9f || _0x41f350(0x1ee) == typeof _0x347c9f)) return _0x347c9f if (void (0x160d + -0x24fd + -0x8 * -0x1de) !== _0x347c9f) throw new TypeError('Derived\x20constructors\x20may\x20only\x20return\x20object\x20or\x20undefined') return _0x58f550(_0x7b2cf6) } function _0x17b234(_0x33316f) { var _0x3601f0 = _0x3390dc() return function () { var _0x4733d6 = w_0x25f3, _0x2848c1, _0x2d0386 = _0x22af63(_0x33316f) if (_0x3601f0) { var _0x252bb3 = _0x22af63(this)[_0x4733d6(0x2ac)] _0x2848c1 = Reflect[_0x4733d6(0x320)](_0x2d0386, arguments, _0x252bb3) } else _0x2848c1 = _0x2d0386[_0x4733d6(0x207)](this, arguments) return _0xf3b17(this, _0x2848c1) } } function _0x2b3a8b(_0x409fbb, _0x508825) { for (; !Object['prototype']['hasOwnProperty']['call'](_0x409fbb, _0x508825) && null !== (_0x409fbb = _0x22af63(_0x409fbb));); return _0x409fbb } function _0x33bfa4() { var _0x1bbf02 = w_0x25f3 return (_0x33bfa4 = _0x1bbf02(0x384) != typeof Reflect && Reflect[_0x1bbf02(0x32b)] ? Reflect[_0x1bbf02(0x32b)][_0x1bbf02(0x301)]() : function (_0x45f38c, _0x4a526c, _0x482f60) { var _0xb2ad90 = _0x1bbf02, _0x53f5d7 = _0x2b3a8b(_0x45f38c, _0x4a526c) if (_0x53f5d7) { var _0x24e05f = Object[_0xb2ad90(0x2a6)](_0x53f5d7, _0x4a526c) return _0x24e05f[_0xb2ad90(0x32b)] ? _0x24e05f[_0xb2ad90(0x32b)][_0xb2ad90(0x334)]( arguments[_0xb2ad90(0x259)] < 0x7f * 0x25 + 0x23f3 + -0x364b ? _0x45f38c : _0x482f60 ) : _0x24e05f[_0xb2ad90(0x2e4)] } })['apply'](this, arguments) } function _0x5b010c(_0x878ee0, _0x27a5c4, _0x35cb40, _0x14e9ba) { var _0x1c5f60 = w_0x25f3 return (_0x5b010c = 'undefined' != typeof Reflect && Reflect[_0x1c5f60(0x1e4)] ? Reflect[_0x1c5f60(0x1e4)] : function (_0xc1d4d, _0x3a32f8, _0x25436d, _0x5ef6e3) { var _0x43a591 = _0x1c5f60, _0x23d91e, _0x5ac459 = _0x2b3a8b(_0xc1d4d, _0x3a32f8) if (_0x5ac459) { if ((_0x23d91e = Object[_0x43a591(0x2a6)](_0x5ac459, _0x3a32f8))[_0x43a591(0x1e4)]) return _0x23d91e['set'][_0x43a591(0x334)](_0x5ef6e3, _0x25436d), !(0x4d * -0x59 + -0x1 * -0x3d6 + 0x16ef) if (!_0x23d91e[_0x43a591(0x2e3)]) return !(-0x2691 + 0x9e * 0x25 + 0xfbc) } if ((_0x23d91e = Object['getOwnPropertyDescriptor'](_0x5ef6e3, _0x3a32f8))) { if (!_0x23d91e[_0x43a591(0x2e3)]) return !(0x14d + -0x1 * -0x29b + -0x3e7) ; (_0x23d91e[_0x43a591(0x2e4)] = _0x25436d), Object[_0x43a591(0x175)](_0x5ef6e3, _0x3a32f8, _0x23d91e) } else _0x4a7824(_0x5ef6e3, _0x3a32f8, _0x25436d) return !(0x295 + -0xa39 * -0x2 + -0x1707) })(_0x878ee0, _0x27a5c4, _0x35cb40, _0x14e9ba) } function _0x2732a4(_0x24a602, _0x194547, _0x16a7b5, _0x8913b1, _0x531d0d) { var _0x16563f = w_0x25f3 if (!_0x5b010c(_0x24a602, _0x194547, _0x16a7b5, _0x8913b1 || _0x24a602) && _0x531d0d) throw new TypeError(_0x16563f(0x34e)) return _0x16a7b5 } function _0x281bf3(_0x4564b4, _0x1f4153) { var _0x10b792 = w_0x25f3 return ( _0x1f4153 || (_0x1f4153 = _0x4564b4[_0x10b792(0x2a5)](0x1017 + 0x1cb3 + 0x2 * -0x1665)), Object[_0x10b792(0x198)]( Object[_0x10b792(0x36c)](_0x4564b4, { raw: { value: Object[_0x10b792(0x198)](_0x1f4153) } }) ) ) } function _0x2d5f0c(_0x18863e, _0x13e8d4) { var _0x47a3d1 = w_0x25f3 return ( _0x13e8d4 || (_0x13e8d4 = _0x18863e['slice'](0x8f1 * 0x1 + 0x1 * 0x1e1f + -0x7d * 0x50)), (_0x18863e[_0x47a3d1(0x2ab)] = _0x13e8d4), _0x18863e ) } function _0x246229(_0x5e71a0) { var _0x47c977 = w_0x25f3 throw new TypeError('\x22' + _0x5e71a0 + _0x47c977(0x338)) } function _0x5db7bf(_0x51f915) { throw new TypeError('\x22' + _0x51f915 + '\x22\x20is\x20write-only') } function _0x2275f4(_0x42246e) { var _0x2f7351 = w_0x25f3 throw new ReferenceError(_0x2f7351(0x1c7) + _0x42246e + '\x22\x20cannot\x20be\x20referenced\x20in\x20computed\x20property\x20keys.') } function _0x516c2b() { } function _0xab4ac9(_0xcde017) { throw new ReferenceError(_0xcde017 + '\x20is\x20not\x20defined\x20-\x20temporal\x20dead\x20zone') } function _0x5b377b(_0x5f4fa5, _0x2f492b) { return _0x5f4fa5 === _0x516c2b ? _0xab4ac9(_0x2f492b) : _0x5f4fa5 } function _0x5096de(_0x3b53c6, _0x3225c3) { return _0x1ae312(_0x3b53c6) || _0x19d66a(_0x3b53c6, _0x3225c3) || _0x525331(_0x3b53c6, _0x3225c3) || _0x25b697() } function _0x1dff6c(_0x3a7a63, _0x147620) { return _0x1ae312(_0x3a7a63) || _0x376fd5(_0x3a7a63, _0x147620) || _0x525331(_0x3a7a63, _0x147620) || _0x25b697() } function _0x5c885(_0x3953c0) { return _0x1ae312(_0x3953c0) || _0x1853c6(_0x3953c0) || _0x525331(_0x3953c0) || _0x25b697() } function _0x534083(_0x3396cf) { return _0x1ccd19(_0x3396cf) || _0x1853c6(_0x3396cf) || _0x525331(_0x3396cf) || _0x542337() } function _0x1ccd19(_0x15e4f0) { var _0x384cbb = w_0x25f3 if (Array[_0x384cbb(0x2af)](_0x15e4f0)) return _0x537c83(_0x15e4f0) } function _0x1ae312(_0x4bfad0) { var _0x3bc5ad = w_0x25f3 if (Array[_0x3bc5ad(0x2af)](_0x4bfad0)) return _0x4bfad0 } function _0x4bbf4b(_0x33a831, _0x181a3c, _0x135270) { var _0x5bf329 = w_0x25f3 if (_0x181a3c && !Array[_0x5bf329(0x2af)](_0x181a3c) && _0x5bf329(0x28b) == typeof _0x181a3c[_0x5bf329(0x259)]) { var _0x43388b = _0x181a3c[_0x5bf329(0x259)] return _0x537c83(_0x181a3c, void (0xb * -0x29 + 0x387 + -0x2 * 0xe2) !== _0x135270 && _0x135270 < _0x43388b ? _0x135270 : _0x43388b) } return _0x33a831(_0x181a3c, _0x135270) } function _0x1853c6(_0x3086ca) { var _0x3e6030 = w_0x25f3 if ((_0x3e6030(0x384) != typeof Symbol && null != _0x3086ca[Symbol[_0x3e6030(0x3b3)]]) || null != _0x3086ca[_0x3e6030(0x1dd)]) return Array['from'](_0x3086ca) } function _0x525331(_0x1ceb3f, _0x38a668) { var _0x2b5250 = w_0x25f3 if (_0x1ceb3f) { if (_0x2b5250(0x33c) == typeof _0x1ceb3f) return _0x537c83(_0x1ceb3f, _0x38a668) var _0x2821d9 = Object[_0x2b5250(0x344)][_0x2b5250(0x3ae)] [_0x2b5250(0x334)](_0x1ceb3f) ['slice'](0x2ae * -0x7 + 0x1 * 0x2181 + 0xeb7 * -0x1, -(-0x1d * -0xec + 0x2 * -0x32 + -0x1a57)) return ( _0x2b5250(0x2eb) === _0x2821d9 && _0x1ceb3f[_0x2b5250(0x2ac)] && (_0x2821d9 = _0x1ceb3f[_0x2b5250(0x2ac)]['name']), 'Map' === _0x2821d9 || _0x2b5250(0x160) === _0x2821d9 ? Array[_0x2b5250(0x29c)](_0x1ceb3f) : _0x2b5250(0x27f) === _0x2821d9 || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/[_0x2b5250(0x22b)](_0x2821d9) ? _0x537c83(_0x1ceb3f, _0x38a668) : void (-0x1 * 0xf34 + 0x12e6 + 0x1d9 * -0x2) ) } } function _0x537c83(_0x1cc46a, _0xca9940) { var _0x4c66e3 = w_0x25f3 ; (null == _0xca9940 || _0xca9940 > _0x1cc46a[_0x4c66e3(0x259)]) && (_0xca9940 = _0x1cc46a[_0x4c66e3(0x259)]) for (var _0x3859e4 = 0x1fe3 * 0x1 + -0x22be + 0x2db, _0x3a8ed3 = new Array(_0xca9940); _0x3859e4 < _0xca9940; _0x3859e4++) _0x3a8ed3[_0x3859e4] = _0x1cc46a[_0x3859e4] return _0x3a8ed3 } function _0x542337() { var _0x1d894c = w_0x25f3 throw new TypeError(_0x1d894c(0x3a8)) } function _0x25b697() { throw new TypeError( 'Invalid\x20attempt\x20to\x20destructure\x20non-iterable\x20instance.\x0aIn\x20order\x20to\x20be\x20iterable,\x20non-array\x20objects\x20must\x20have\x20a\x20[Symbol.iterator]()\x20method.' ) } function _0x350075(_0x189dc6, _0x3f6be9) { var _0x464771 = w_0x25f3, _0x199147 = (_0x464771(0x384) != typeof Symbol && _0x189dc6[Symbol[_0x464771(0x3b3)]]) || _0x189dc6[_0x464771(0x1dd)] if (!_0x199147) { if ( Array['isArray'](_0x189dc6) || (_0x199147 = _0x525331(_0x189dc6)) || (_0x3f6be9 && _0x189dc6 && _0x464771(0x28b) == typeof _0x189dc6[_0x464771(0x259)]) ) { _0x199147 && (_0x189dc6 = _0x199147) var _0x544a3f = 0x1fd2 + 0x1 * -0x1ad5 + 0x4fd * -0x1, _0x5b20ae = function () { } return { s: _0x5b20ae, n: function () { var _0x4c93f0 = _0x464771 return _0x544a3f >= _0x189dc6[_0x4c93f0(0x259)] ? { done: !(-0x1aaa * 0x1 + -0x126e * 0x1 + 0x2d18) } : { done: !(0x7 * -0x205 + 0x1d44 + -0xf20), value: _0x189dc6[_0x544a3f++] } }, e: function (_0x4d8393) { throw _0x4d8393 }, f: _0x5b20ae } } throw new TypeError(_0x464771(0x2ae)) } var _0x23cdd3, _0x5bcfbb = !(0x1 * -0x810 + -0xb3 * 0x2f + 0x1 * 0x28ed), _0x4db4fd = !(0x221 + 0x62e * 0x5 + 0x3 * -0xb02) return { s: function () { _0x199147 = _0x199147['call'](_0x189dc6) }, n: function () { var _0x30f507 = _0x464771, _0x2382b6 = _0x199147['next']() return (_0x5bcfbb = _0x2382b6[_0x30f507(0x1e3)]), _0x2382b6 }, e: function (_0x3b0f24) { ; (_0x4db4fd = !(0x18e0 + 0x2 * 0x214 + -0x1d08)), (_0x23cdd3 = _0x3b0f24) }, f: function () { var _0x22fdad = _0x464771 try { _0x5bcfbb || null == _0x199147[_0x22fdad(0x2fd)] || _0x199147[_0x22fdad(0x2fd)]() } finally { if (_0x4db4fd) throw _0x23cdd3 } } } } function _0x37af30(_0x37ea9e, _0x2388a0) { var _0x3701de = w_0x25f3, _0x2ac940 = ('undefined' != typeof Symbol && _0x37ea9e[Symbol[_0x3701de(0x3b3)]]) || _0x37ea9e['@@iterator'] if (_0x2ac940) return (_0x2ac940 = _0x2ac940['call'](_0x37ea9e))[_0x3701de(0x389)][_0x3701de(0x301)](_0x2ac940) if ( Array[_0x3701de(0x2af)](_0x37ea9e) || (_0x2ac940 = _0x525331(_0x37ea9e)) || (_0x2388a0 && _0x37ea9e && 'number' == typeof _0x37ea9e[_0x3701de(0x259)]) ) { _0x2ac940 && (_0x37ea9e = _0x2ac940) var _0x1dcac8 = 0x1d * -0x11a + -0x1f * 0xc7 + -0x380b * -0x1 return function () { var _0x306ed0 = _0x3701de return _0x1dcac8 >= _0x37ea9e[_0x306ed0(0x259)] ? { done: !(-0x29d + 0x5fb * -0x1 + 0x898) } : { done: !(-0x6e * 0x4f + 0x2311 + -0x11e), value: _0x37ea9e[_0x1dcac8++] } } } throw new TypeError(_0x3701de(0x2ae)) } function _0x5362e1(_0x4cd55f) { return function () { var _0x58617f = w_0x25f3, _0x183c06 = _0x4cd55f['apply'](this, arguments) return _0x183c06[_0x58617f(0x389)](), _0x183c06 } } function _0x4ad3b0(_0x460146, _0x32cf07) { var _0x271683 = w_0x25f3 if (_0x271683(0x17d) != typeof _0x460146 || null === _0x460146) return _0x460146 var _0xa9fa9c = _0x460146[Symbol['toPrimitive']] if (void (0x21b4 + 0x5 * 0x4c7 + 0x3997 * -0x1) !== _0xa9fa9c) { var _0x560849 = _0xa9fa9c['call'](_0x460146, _0x32cf07 || _0x271683(0x1d3)) if ('object' != typeof _0x560849) return _0x560849 throw new TypeError(_0x271683(0x358)) } return ('string' === _0x32cf07 ? String : Number)(_0x460146) } function _0x32e885(_0x225644) { var _0x1eb479 = w_0x25f3, _0x45c5d4 = _0x4ad3b0(_0x225644, _0x1eb479(0x33c)) return _0x1eb479(0x2ed) == typeof _0x45c5d4 ? _0x45c5d4 : String(_0x45c5d4) } function _0xf47dc3(_0x1d62a3, _0xeb8470) { var _0x31107e = w_0x25f3 throw new Error(_0x31107e(0x1ff)) } function _0x9d8dd5(_0x238b59, _0x206a18, _0x4378c6, _0x532e73) { var _0x340b07 = w_0x25f3 _0x4378c6 && Object[_0x340b07(0x175)](_0x238b59, _0x206a18, { enumerable: _0x4378c6['enumerable'], configurable: _0x4378c6[_0x340b07(0x2bc)], writable: _0x4378c6[_0x340b07(0x2e3)], value: _0x4378c6[_0x340b07(0x2d0)] ? _0x4378c6['initializer'][_0x340b07(0x334)](_0x532e73) : void (-0x1ae6 + -0x1 * -0xf6b + 0xb7b * 0x1) }) } function _0x271739(_0xb876c5, _0x285720, _0x361de9, _0x52c079, _0x38a76d) { var _0x26b61e = w_0x25f3, _0x25c883 = {} return ( Object['keys'](_0x52c079)[_0x26b61e(0x254)](function (_0xd1a198) { _0x25c883[_0xd1a198] = _0x52c079[_0xd1a198] }), (_0x25c883[_0x26b61e(0x23a)] = !!_0x25c883[_0x26b61e(0x23a)]), (_0x25c883[_0x26b61e(0x2bc)] = !!_0x25c883[_0x26b61e(0x2bc)]), (_0x26b61e(0x2e4) in _0x25c883 || _0x25c883['initializer']) && (_0x25c883[_0x26b61e(0x2e3)] = !(0x21e8 + -0x7cf * -0x5 + -0x48f3)), (_0x25c883 = _0x361de9[_0x26b61e(0x2a5)]() [_0x26b61e(0x2f3)]() [_0x26b61e(0x376)](function (_0x490c4a, _0x3636f6) { return _0x3636f6(_0xb876c5, _0x285720, _0x490c4a) || _0x490c4a }, _0x25c883)), _0x38a76d && void (0x1050 + 0x1 * 0x121f + -0x226f) !== _0x25c883[_0x26b61e(0x2d0)] && ((_0x25c883[_0x26b61e(0x2e4)] = _0x25c883[_0x26b61e(0x2d0)] ? _0x25c883[_0x26b61e(0x2d0)][_0x26b61e(0x334)](_0x38a76d) : void (0x1392 + -0xbe * 0x23 + -0x1 * -0x668)), (_0x25c883[_0x26b61e(0x2d0)] = void (-0x1 * -0x1b9a + 0x7f7 + -0x2391 * 0x1))), void (0x53 * 0xb + 0xa2 * -0xf + 0x5ed) === _0x25c883[_0x26b61e(0x2d0)] && (Object[_0x26b61e(0x175)](_0xb876c5, _0x285720, _0x25c883), (_0x25c883 = null)), _0x25c883 ) } ; (_0x137ba2['prototype'][(_0x5612de(0x1ee) == typeof Symbol && Symbol[_0x5612de(0x17c)]) || _0x5612de(0x230)] = function () { return this }), (_0x137ba2[_0x5612de(0x344)]['next'] = function (_0x4262ae) { var _0x1543b4 = _0x5612de return this[_0x1543b4(0x1b1)](_0x1543b4(0x389), _0x4262ae) }), (_0x137ba2[_0x5612de(0x344)]['throw'] = function (_0x29bafe) { var _0x4c6950 = _0x5612de return this[_0x4c6950(0x1b1)]('throw', _0x29bafe) }), (_0x137ba2[_0x5612de(0x344)][_0x5612de(0x2fd)] = function (_0x49a53d) { var _0x58f790 = _0x5612de return this[_0x58f790(0x1b1)](_0x58f790(0x2fd), _0x49a53d) }) var _0x371360 = 0x11 * -0x20 + 0x88 * -0x1f + 0x1298, _0x4d6c78, _0x312e19, _0x2a32a1, _0x371ac2 function _0x2ca065(_0x4c2f2d) { var _0x4415ed = _0x5612de return _0x4415ed(0x365) + _0x371360++ + '_' + _0x4c2f2d } function _0x33f649(_0x59611c, _0xb8c4c1) { var _0x22f43f = _0x5612de if (!Object['prototype'][_0x22f43f(0x3b8)][_0x22f43f(0x334)](_0x59611c, _0xb8c4c1)) throw new TypeError(_0x22f43f(0x271)) return _0x59611c } function _0x4c53b8(_0x467264, _0x1c39b3) { var _0x12fb5e = _0x5612de return _0x1de0ff(_0x467264, _0x3feef3(_0x467264, _0x1c39b3, _0x12fb5e(0x32b))) } function _0xf01d58(_0x248ad, _0xd514dd, _0x4ffcbe) { var _0x2a0763 = _0x5612de return _0x30760d(_0x248ad, _0x3feef3(_0x248ad, _0xd514dd, _0x2a0763(0x1e4)), _0x4ffcbe), _0x4ffcbe } function _0x3ff428(_0x59a12f, _0x2e6e68) { var _0x1a4f4c = _0x5612de return _0x1af7ca(_0x59a12f, _0x3feef3(_0x59a12f, _0x2e6e68, _0x1a4f4c(0x1e4))) } function _0x3feef3(_0x76bca3, _0x49ed2b, _0xf40042) { var _0x26b65c = _0x5612de if (!_0x49ed2b[_0x26b65c(0x2fc)](_0x76bca3)) throw new TypeError(_0x26b65c(0x2ad) + _0xf40042 + _0x26b65c(0x2bd)) return _0x49ed2b[_0x26b65c(0x32b)](_0x76bca3) } function _0x46f318(_0x2345ad, _0x29e732, _0x5d3874) { var _0x1785a7 = _0x5612de return _0x3fbf28(_0x2345ad, _0x29e732), _0x234ff5(_0x5d3874, _0x1785a7(0x32b)), _0x1de0ff(_0x2345ad, _0x5d3874) } function _0x3d490a(_0x421876, _0x556ee1, _0x489ccf, _0x32c792) { return _0x3fbf28(_0x421876, _0x556ee1), _0x234ff5(_0x489ccf, 'set'), _0x30760d(_0x421876, _0x489ccf, _0x32c792), _0x32c792 } function _0x1f2159(_0x3c139e, _0xf1d93, _0xa6753b) { return _0x3fbf28(_0x3c139e, _0xf1d93), _0xa6753b } function _0x2fcc7b() { var _0x52da1e = _0x5612de throw new TypeError(_0x52da1e(0x1bd)) } function _0x1de0ff(_0x35f1cc, _0x2cd6a2) { var _0x331169 = _0x5612de return _0x2cd6a2[_0x331169(0x32b)] ? _0x2cd6a2[_0x331169(0x32b)][_0x331169(0x334)](_0x35f1cc) : _0x2cd6a2[_0x331169(0x2e4)] } function _0x30760d(_0x26c16c, _0x3bf250, _0x4bb532) { var _0x4b5758 = _0x5612de if (_0x3bf250['set']) _0x3bf250['set'][_0x4b5758(0x334)](_0x26c16c, _0x4bb532) else { if (!_0x3bf250['writable']) throw new TypeError('attempted\x20to\x20set\x20read\x20only\x20private\x20field') _0x3bf250['value'] = _0x4bb532 } } function _0x1af7ca(_0x38569e, _0x4d9da9) { var _0x8504a5 = _0x5612de if (_0x4d9da9[_0x8504a5(0x1e4)]) return ( _0x8504a5(0x36f) in _0x4d9da9 || (_0x4d9da9['__destrObj'] = { set value(_0xa3d23) { var _0x3d920b = _0x8504a5 _0x4d9da9[_0x3d920b(0x1e4)][_0x3d920b(0x334)](_0x38569e, _0xa3d23) } }), _0x4d9da9['__destrObj'] ) if (!_0x4d9da9[_0x8504a5(0x2e3)]) throw new TypeError('attempted\x20to\x20set\x20read\x20only\x20private\x20field') return _0x4d9da9 } function _0x153ad5(_0x361a17, _0x4bf341, _0x38ef34) { var _0x36fea3 = _0x5612de return _0x3fbf28(_0x361a17, _0x4bf341), _0x234ff5(_0x38ef34, _0x36fea3(0x1e4)), _0x1af7ca(_0x361a17, _0x38ef34) } function _0x3fbf28(_0x1609bf, _0x372dbd) { if (_0x1609bf !== _0x372dbd) throw new TypeError('Private\x20static\x20access\x20of\x20wrong\x20provenance') } function _0x234ff5(_0x5dcf40, _0xa0e3be) { var _0x4d5828 = _0x5612de if (void (0x9 * 0x3b9 + -0x7 * -0x2bb + -0x382 * 0xf) === _0x5dcf40) throw new TypeError(_0x4d5828(0x2ad) + _0xa0e3be + '\x20private\x20static\x20field\x20before\x20its\x20declaration') } function _0x3cd893(_0x4d4ac2, _0x117b1a, _0x13ebad, _0x227002) { var _0x404d8d = _0x5612de, _0x21250e = _0xdaf8f6() if (_0x227002) { for (var _0x1ad96b = -0x1 * -0x109d + 0x157 + -0x11f4; _0x1ad96b < _0x227002[_0x404d8d(0x259)]; _0x1ad96b++) _0x21250e = _0x227002[_0x1ad96b](_0x21250e) } var _0x176094 = _0x117b1a(function (_0x32bc32) { var _0x1f970f = _0x404d8d _0x21250e[_0x1f970f(0x313)](_0x32bc32, _0x1fa626[_0x1f970f(0x265)]) }, _0x13ebad), _0x1fa626 = _0x21250e[_0x404d8d(0x2df)](_0x872852(_0x176094['d'][_0x404d8d(0x1cb)](_0x210308)), _0x4d4ac2) return ( _0x21250e[_0x404d8d(0x217)](_0x176094['F'], _0x1fa626[_0x404d8d(0x265)]), _0x21250e[_0x404d8d(0x165)](_0x176094['F'], _0x1fa626[_0x404d8d(0x39c)]) ) } function _0xdaf8f6() { var _0x3fa41d = _0x5612de _0xdaf8f6 = function () { return _0x513b0e } var _0x513b0e = { elementsDefinitionOrder: [[_0x3fa41d(0x25a)], [_0x3fa41d(0x23c)]], initializeInstanceElements: function (_0x179aa6, _0x25d5cd) { var _0x557071 = _0x3fa41d ;[_0x557071(0x25a), _0x557071(0x23c)][_0x557071(0x254)](function (_0x2476e8) { var _0x9b5c0b = _0x557071 _0x25d5cd[_0x9b5c0b(0x254)](function (_0x299a4a) { var _0x53da95 = _0x9b5c0b _0x299a4a['kind'] === _0x2476e8 && _0x53da95(0x235) === _0x299a4a[_0x53da95(0x215)] && this[_0x53da95(0x2e1)](_0x179aa6, _0x299a4a) }, this) }, this) }, initializeClassElements: function (_0x300a4c, _0x38031f) { var _0x450502 = _0x3fa41d, _0x4e1581 = _0x300a4c[_0x450502(0x344)] ;[_0x450502(0x25a), _0x450502(0x23c)]['forEach'](function (_0x2fde74) { _0x38031f['forEach'](function (_0xe5e082) { var _0x123341 = w_0x25f3, _0x174ec4 = _0xe5e082[_0x123341(0x215)] if (_0xe5e082[_0x123341(0x26f)] === _0x2fde74 && (_0x123341(0x396) === _0x174ec4 || _0x123341(0x344) === _0x174ec4)) { var _0x184ef0 = _0x123341(0x396) === _0x174ec4 ? _0x300a4c : _0x4e1581 this[_0x123341(0x2e1)](_0x184ef0, _0xe5e082) } }, this) }, this) }, defineClassElement: function (_0x2e2a2c, _0x5db810) { var _0x522104 = _0x3fa41d, _0x2d7321 = _0x5db810['descriptor'] if (_0x522104(0x23c) === _0x5db810[_0x522104(0x26f)]) { var _0x554ae6 = _0x5db810[_0x522104(0x2d0)] _0x2d7321 = { enumerable: _0x2d7321[_0x522104(0x23a)], writable: _0x2d7321[_0x522104(0x2e3)], configurable: _0x2d7321[_0x522104(0x2bc)], value: void (-0x1 * 0x3bd + 0x1ef9 + -0x1b3c) === _0x554ae6 ? void (0x1 * 0x1afe + 0xcd0 + 0x7f6 * -0x5) : _0x554ae6[_0x522104(0x334)](_0x2e2a2c) } } Object[_0x522104(0x175)](_0x2e2a2c, _0x5db810['key'], _0x2d7321) }, decorateClass: function (_0x4d5101, _0x1a7961) { var _0x129760 = _0x3fa41d, _0x1a31cc = [], _0x3f7e89 = [], _0xf8b039 = { static: [], prototype: [], own: [] } if ( (_0x4d5101[_0x129760(0x254)](function (_0x5c0ba5) { var _0x27d627 = _0x129760 this[_0x27d627(0x33d)](_0x5c0ba5, _0xf8b039) }, this), _0x4d5101[_0x129760(0x254)](function (_0x239102) { var _0x151241 = _0x129760 if (!_0x51f3b5(_0x239102)) return _0x1a31cc[_0x151241(0x36e)](_0x239102) var _0x43ec40 = this[_0x151241(0x1ac)](_0x239102, _0xf8b039) _0x1a31cc[_0x151241(0x36e)](_0x43ec40[_0x151241(0x206)]), _0x1a31cc[_0x151241(0x36e)]['apply'](_0x1a31cc, _0x43ec40[_0x151241(0x3bc)]), _0x3f7e89[_0x151241(0x36e)]['apply'](_0x3f7e89, _0x43ec40[_0x151241(0x39c)]) }, this), !_0x1a7961) ) return { elements: _0x1a31cc, finishers: _0x3f7e89 } var _0x857545 = this[_0x129760(0x34c)](_0x1a31cc, _0x1a7961) return ( _0x3f7e89['push'][_0x129760(0x207)](_0x3f7e89, _0x857545[_0x129760(0x39c)]), (_0x857545[_0x129760(0x39c)] = _0x3f7e89), _0x857545 ) }, addElementPlacement: function (_0x9cedb8, _0x4c2171, _0xa6e6c8) { var _0x5d3aa1 = _0x3fa41d, _0x33e5e0 = _0x4c2171[_0x9cedb8[_0x5d3aa1(0x215)]] if (!_0xa6e6c8 && -(-0x1a83 + -0x1 * -0x16ee + 0x99 * 0x6) !== _0x33e5e0['indexOf'](_0x9cedb8['key'])) throw new TypeError('Duplicated\x20element\x20(' + _0x9cedb8[_0x5d3aa1(0x392)] + ')') _0x33e5e0[_0x5d3aa1(0x36e)](_0x9cedb8[_0x5d3aa1(0x392)]) }, decorateElement: function (_0x463258, _0x11d852) { var _0x495609 = _0x3fa41d for ( var _0x4c5aa5 = [], _0x46b095 = [], _0x106243 = _0x463258['decorators'], _0x195d25 = _0x106243[_0x495609(0x259)] - (-0x1d5c * -0x1 + 0x1aa9 + 0x956 * -0x6); _0x195d25 >= 0x18ee + 0x1 * 0x1c19 + 0xf * -0x389; _0x195d25-- ) { var _0x425891 = _0x11d852[_0x463258[_0x495609(0x215)]] _0x425891[_0x495609(0x2ec)](_0x425891[_0x495609(0x2c5)](_0x463258[_0x495609(0x392)]), 0x1 * 0xca7 + -0xaf * -0xb + -0x142b) var _0x30722d = this[_0x495609(0x372)](_0x463258), _0x15a14c = this[_0x495609(0x18a)]((0x61 * 0x2d + 0x1545 + -0x1 * 0x2652, _0x106243[_0x195d25])(_0x30722d) || _0x30722d) ; (_0x463258 = _0x15a14c['element']), this['addElementPlacement'](_0x463258, _0x11d852), _0x15a14c[_0x495609(0x2f4)] && _0x46b095[_0x495609(0x36e)](_0x15a14c[_0x495609(0x2f4)]) var _0x98e9dc = _0x15a14c[_0x495609(0x3bc)] if (_0x98e9dc) { for (var _0x56dd4d = 0xb * 0x12e + -0x1f17 + -0x121d * -0x1; _0x56dd4d < _0x98e9dc[_0x495609(0x259)]; _0x56dd4d++) this[_0x495609(0x33d)](_0x98e9dc[_0x56dd4d], _0x11d852) _0x4c5aa5[_0x495609(0x36e)]['apply'](_0x4c5aa5, _0x98e9dc) } } return { element: _0x463258, finishers: _0x46b095, extras: _0x4c5aa5 } }, decorateConstructor: function (_0x2a4d32, _0x2666ea) { var _0x5e156c = _0x3fa41d for ( var _0xb2f010 = [], _0x17b2e4 = _0x2666ea[_0x5e156c(0x259)] - (0x21c0 + -0xc8e * 0x2 + -0x8a3 * 0x1); _0x17b2e4 >= -0x1c70 + -0x1 * -0x1256 + -0x1af * -0x6; _0x17b2e4-- ) { var _0x222759 = this[_0x5e156c(0x193)](_0x2a4d32), _0xc41f78 = this[_0x5e156c(0x324)]((0x1f46 + 0x81d * 0x2 + -0x5f * 0x80, _0x2666ea[_0x17b2e4])(_0x222759) || _0x222759) if ( (void (0x1373 + 0x2b1 * -0x2 + -0x1 * 0xe11) !== _0xc41f78[_0x5e156c(0x2f4)] && _0xb2f010[_0x5e156c(0x36e)](_0xc41f78[_0x5e156c(0x2f4)]), void (0x31 * -0xb5 + -0x11 * 0x67 + 0x84c * 0x5) !== _0xc41f78['elements']) ) { _0x2a4d32 = _0xc41f78[_0x5e156c(0x265)] for ( var _0x38c2da = -0x1 * -0xc12 + 0x7 * -0x28d + 0x5c9; _0x38c2da < _0x2a4d32[_0x5e156c(0x259)] - (0x59f * 0x6 + -0x1 * -0x1c6d + 0x25 * -0x1ae); _0x38c2da++ ) for (var _0x2950ed = _0x38c2da + (0x1b91 * 0x1 + -0xbc0 + -0x8 * 0x1fa); _0x2950ed < _0x2a4d32['length']; _0x2950ed++) if ( _0x2a4d32[_0x38c2da][_0x5e156c(0x392)] === _0x2a4d32[_0x2950ed][_0x5e156c(0x392)] && _0x2a4d32[_0x38c2da][_0x5e156c(0x215)] === _0x2a4d32[_0x2950ed][_0x5e156c(0x215)] ) throw new TypeError(_0x5e156c(0x367) + _0x2a4d32[_0x38c2da][_0x5e156c(0x392)] + ')') } } return { elements: _0x2a4d32, finishers: _0xb2f010 } }, fromElementDescriptor: function (_0x4a43c8) { var _0x302152 = _0x3fa41d, _0x406d6b = { kind: _0x4a43c8[_0x302152(0x26f)], key: _0x4a43c8['key'], placement: _0x4a43c8['placement'], descriptor: _0x4a43c8[_0x302152(0x20f)] } return ( Object[_0x302152(0x175)](_0x406d6b, Symbol[_0x302152(0x1c0)], { value: _0x302152(0x1e8), configurable: !(-0x1b3a + 0x21bb * 0x1 + -0x14d * 0x5) }), _0x302152(0x23c) === _0x4a43c8['kind'] && (_0x406d6b[_0x302152(0x2d0)] = _0x4a43c8['initializer']), _0x406d6b ) }, toElementDescriptors: function (_0x14be66) { if (void (0x1f48 + -0x19fe + 0x2a5 * -0x2) !== _0x14be66) return _0x5c885(_0x14be66)['map'](function (_0x170c20) { var _0x5285ee = w_0x25f3, _0xf0c7ce = this[_0x5285ee(0x25e)](_0x170c20) return ( this['disallowProperty'](_0x170c20, _0x5285ee(0x2f4), _0x5285ee(0x21f)), this[_0x5285ee(0x21a)](_0x170c20, _0x5285ee(0x3bc), _0x5285ee(0x21f)), _0xf0c7ce ) }, this) }, toElementDescriptor: function (_0x4c8a60) { var _0x1fc4d7 = _0x3fa41d, _0x33cfb6 = String(_0x4c8a60[_0x1fc4d7(0x26f)]) if (_0x1fc4d7(0x25a) !== _0x33cfb6 && _0x1fc4d7(0x23c) !== _0x33cfb6) throw new TypeError( 'An\x20element\x20descriptor\x27s\x20.kind\x20property\x20must\x20be\x20either\x20\x22method\x22\x20or\x20\x22field\x22,\x20but\x20a\x20decorator\x20created\x20an\x20element\x20descriptor\x20with\x20.kind\x20\x22' + _0x33cfb6 + '\x22' ) var _0xebb768 = _0x32e885(_0x4c8a60[_0x1fc4d7(0x392)]), _0x52ab63 = String(_0x4c8a60[_0x1fc4d7(0x215)]) if (_0x1fc4d7(0x396) !== _0x52ab63 && _0x1fc4d7(0x344) !== _0x52ab63 && _0x1fc4d7(0x235) !== _0x52ab63) throw new TypeError(_0x1fc4d7(0x2b5) + _0x52ab63 + '\x22') var _0x33ee46 = _0x4c8a60[_0x1fc4d7(0x20f)] this[_0x1fc4d7(0x21a)](_0x4c8a60, 'elements', _0x1fc4d7(0x21f)) var _0x1ca161 = { kind: _0x33cfb6, key: _0xebb768, placement: _0x52ab63, descriptor: Object[_0x1fc4d7(0x2a0)]({}, _0x33ee46) } return ( _0x1fc4d7(0x23c) !== _0x33cfb6 ? this[_0x1fc4d7(0x21a)](_0x4c8a60, _0x1fc4d7(0x2d0), _0x1fc4d7(0x28d)) : (this['disallowProperty'](_0x33ee46, _0x1fc4d7(0x32b), _0x1fc4d7(0x277)), this['disallowProperty'](_0x33ee46, 'set', _0x1fc4d7(0x277)), this['disallowProperty'](_0x33ee46, _0x1fc4d7(0x2e4), _0x1fc4d7(0x277)), (_0x1ca161['initializer'] = _0x4c8a60[_0x1fc4d7(0x2d0)])), _0x1ca161 ) }, toElementFinisherExtras: function (_0x53b840) { var _0x1157c0 = _0x3fa41d return { element: this[_0x1157c0(0x25e)](_0x53b840), finisher: _0x22df7b(_0x53b840, _0x1157c0(0x2f4)), extras: this[_0x1157c0(0x370)](_0x53b840['extras']) } }, fromClassDescriptor: function (_0x30c308) { var _0x482b04 = _0x3fa41d, _0xf231c1 = { kind: _0x482b04(0x19c), elements: _0x30c308['map'](this[_0x482b04(0x372)], this) } return ( Object[_0x482b04(0x175)](_0xf231c1, Symbol[_0x482b04(0x1c0)], { value: _0x482b04(0x1e8), configurable: !(0xf * -0xf1 + 0x1 * -0xcfe + -0x1b1d * -0x1) }), _0xf231c1 ) }, toClassDescriptor: function (_0x178ca0) { var _0x2520a1 = _0x3fa41d, _0x79f336 = String(_0x178ca0[_0x2520a1(0x26f)]) if ('class' !== _0x79f336) throw new TypeError( 'A\x20class\x20descriptor\x27s\x20.kind\x20property\x20must\x20be\x20\x22class\x22,\x20but\x20a\x20decorator\x20created\x20a\x20class\x20descriptor\x20with\x20.kind\x20\x22' + _0x79f336 + '\x22' ) this['disallowProperty'](_0x178ca0, _0x2520a1(0x392), 'A\x20class\x20descriptor'), this[_0x2520a1(0x21a)](_0x178ca0, _0x2520a1(0x215), 'A\x20class\x20descriptor'), this[_0x2520a1(0x21a)](_0x178ca0, _0x2520a1(0x20f), _0x2520a1(0x1a1)), this['disallowProperty'](_0x178ca0, 'initializer', _0x2520a1(0x1a1)), this[_0x2520a1(0x21a)](_0x178ca0, _0x2520a1(0x3bc), 'A\x20class\x20descriptor') var _0x154e32 = _0x22df7b(_0x178ca0, _0x2520a1(0x2f4)) return { elements: this['toElementDescriptors'](_0x178ca0['elements']), finisher: _0x154e32 } }, runClassFinishers: function (_0x58401c, _0x3ff489) { var _0x4a8de1 = _0x3fa41d for (var _0x5ec766 = 0x13b0 + -0xe05 + 0x1 * -0x5ab; _0x5ec766 < _0x3ff489[_0x4a8de1(0x259)]; _0x5ec766++) { var _0x176fd2 = (0x7d * -0x25 + 0x101 * 0x14 + 0x5 * -0x67, _0x3ff489[_0x5ec766])(_0x58401c) if (void (-0x1 * 0x200 + 0x1c4a + -0x1a4a) !== _0x176fd2) { if (_0x4a8de1(0x1ee) != typeof _0x176fd2) throw new TypeError('Finishers\x20must\x20return\x20a\x20constructor.') _0x58401c = _0x176fd2 } } return _0x58401c }, disallowProperty: function (_0x376492, _0x1998df, _0x46cda4) { var _0x5b24b6 = _0x3fa41d if (void (0x2239 + -0xa67 + -0x17d2) !== _0x376492[_0x1998df]) throw new TypeError(_0x46cda4 + _0x5b24b6(0x232) + _0x1998df + _0x5b24b6(0x2a1)) } } return _0x513b0e } function _0x210308(_0x5bae0) { var _0x509268 = _0x5612de, _0x2061f6, _0x1daa96 = _0x32e885(_0x5bae0['key']) _0x509268(0x25a) === _0x5bae0[_0x509268(0x26f)] ? (_0x2061f6 = { value: _0x5bae0[_0x509268(0x2e4)], writable: !(-0x286 + -0x3 * -0x83b + -0x162b), configurable: !(-0x1 * -0x13f9 + -0x2 * -0x1127 + -0x3647), enumerable: !(-0x210 * -0x1 + 0xf43 * -0x2 + 0x1c77) }) : _0x509268(0x32b) === _0x5bae0[_0x509268(0x26f)] ? (_0x2061f6 = { get: _0x5bae0['value'], configurable: !(-0x4 * -0x87 + 0x25b6 + -0x13e9 * 0x2), enumerable: !(0x4 * -0x105 + -0x8 * 0x3b + 0x5ed * 0x1) }) : 'set' === _0x5bae0[_0x509268(0x26f)] ? (_0x2061f6 = { set: _0x5bae0[_0x509268(0x2e4)], configurable: !(-0x1 * -0xd7c + 0x24e2 + -0x325e), enumerable: !(0x246b * -0x1 + -0xbdc + 0x67 * 0x78) }) : _0x509268(0x23c) === _0x5bae0['kind'] && (_0x2061f6 = { configurable: !(-0x7 * 0x7c + 0x0 + -0x1 * -0x364), writable: !(0x10cc + 0x93a + -0x1a06), enumerable: !(-0x339 + -0xfd1 * -0x1 + -0xc98) }) var _0x12b911 = { kind: _0x509268(0x23c) === _0x5bae0[_0x509268(0x26f)] ? _0x509268(0x23c) : 'method', key: _0x1daa96, placement: _0x5bae0[_0x509268(0x396)] ? _0x509268(0x396) : 'field' === _0x5bae0[_0x509268(0x26f)] ? 'own' : _0x509268(0x344), descriptor: _0x2061f6 } return ( _0x5bae0['decorators'] && (_0x12b911[_0x509268(0x1b7)] = _0x5bae0[_0x509268(0x1b7)]), _0x509268(0x23c) === _0x5bae0['kind'] && (_0x12b911['initializer'] = _0x5bae0[_0x509268(0x2e4)]), _0x12b911 ) } function _0x3b2c5d(_0x1d2cd7, _0x5043bf) { var _0x6af88f = _0x5612de void (-0x1c1e + -0x19 * -0xd9 + -0x1 * -0x6ed) !== _0x1d2cd7[_0x6af88f(0x20f)][_0x6af88f(0x32b)] ? (_0x5043bf['descriptor'][_0x6af88f(0x32b)] = _0x1d2cd7['descriptor'][_0x6af88f(0x32b)]) : (_0x5043bf['descriptor']['set'] = _0x1d2cd7[_0x6af88f(0x20f)][_0x6af88f(0x1e4)]) } function _0x872852(_0x11fd7b) { var _0x45b70e = _0x5612de for ( var _0x3d0947 = [], _0x1e20eb = function (_0x3c1862) { var _0x56210d = w_0x25f3 return ( _0x56210d(0x25a) === _0x3c1862[_0x56210d(0x26f)] && _0x3c1862[_0x56210d(0x392)] === _0x44502e['key'] && _0x3c1862[_0x56210d(0x215)] === _0x44502e[_0x56210d(0x215)] ) }, _0x2773ae = -0xdd7 + 0x5 * 0x3f6 + 0x5f7 * -0x1; _0x2773ae < _0x11fd7b[_0x45b70e(0x259)]; _0x2773ae++ ) { var _0x152571, _0x44502e = _0x11fd7b[_0x2773ae] if (_0x45b70e(0x25a) === _0x44502e[_0x45b70e(0x26f)] && (_0x152571 = _0x3d0947['find'](_0x1e20eb))) { if (_0x3f9244(_0x44502e[_0x45b70e(0x20f)]) || _0x3f9244(_0x152571[_0x45b70e(0x20f)])) { if (_0x51f3b5(_0x44502e) || _0x51f3b5(_0x152571)) throw new ReferenceError('Duplicated\x20methods\x20(' + _0x44502e[_0x45b70e(0x392)] + _0x45b70e(0x20b)) _0x152571[_0x45b70e(0x20f)] = _0x44502e[_0x45b70e(0x20f)] } else { if (_0x51f3b5(_0x44502e)) { if (_0x51f3b5(_0x152571)) throw new ReferenceError( 'Decorators\x20can\x27t\x20be\x20placed\x20on\x20different\x20accessors\x20with\x20for\x20the\x20same\x20property\x20(' + _0x44502e['key'] + ').' ) _0x152571[_0x45b70e(0x1b7)] = _0x44502e[_0x45b70e(0x1b7)] } _0x3b2c5d(_0x44502e, _0x152571) } } else _0x3d0947[_0x45b70e(0x36e)](_0x44502e) } return _0x3d0947 } function _0x51f3b5(_0x3b7753) { var _0x46d225 = _0x5612de return _0x3b7753[_0x46d225(0x1b7)] && _0x3b7753['decorators']['length'] } function _0x3f9244(_0x197382) { var _0x1ec41e = _0x5612de return ( void (0xa8 + 0x12a * -0x4 + 0x400) !== _0x197382 && !( void (-0x2 * -0x955 + -0x965 + -0x945) === _0x197382[_0x1ec41e(0x2e4)] && void (-0x403 + 0xd * 0x1e2 + -0x1477) === _0x197382[_0x1ec41e(0x2e3)] ) ) } function _0x22df7b(_0x1a9e0b, _0x4c3aa6) { var _0x2004a6 = _0x5612de, _0x42d7e1 = _0x1a9e0b[_0x4c3aa6] if (void (-0x1ab * -0x11 + -0x2164 + 0x1 * 0x509) !== _0x42d7e1 && _0x2004a6(0x1ee) != typeof _0x42d7e1) throw new TypeError('Expected\x20\x27' + _0x4c3aa6 + _0x2004a6(0x200)) return _0x42d7e1 } function _0x44a779(_0x290bd9, _0x3c4184, _0x356c04) { var _0x5e1d0b = _0x5612de if (!_0x3c4184[_0x5e1d0b(0x2fc)](_0x290bd9)) throw new TypeError(_0x5e1d0b(0x187)) return _0x356c04 } function _0x227cd9(_0x44aab6, _0x47792b) { var _0x50e6e8 = _0x5612de if (_0x47792b[_0x50e6e8(0x2fc)](_0x44aab6)) throw new TypeError('Cannot\x20initialize\x20the\x20same\x20private\x20elements\x20twice\x20on\x20an\x20object') } function _0x41d2eb(_0x2d54de, _0x30b42b, _0x3cc210) { _0x227cd9(_0x2d54de, _0x30b42b), _0x30b42b['set'](_0x2d54de, _0x3cc210) } function _0x4fd04a(_0x1b36b3, _0x1a6559) { var _0x1aaac6 = _0x5612de _0x227cd9(_0x1b36b3, _0x1a6559), _0x1a6559[_0x1aaac6(0x332)](_0x1b36b3) } function _0x4fb313() { throw new TypeError('attempted\x20to\x20reassign\x20private\x20method') } function _0x4e4f66(_0x9f7990) { return _0x9f7990 } _0x5612de(0x1ee) != typeof Object[_0x5612de(0x2a0)] && Object['defineProperty'](Object, _0x5612de(0x2a0), { value: function (_0x478fa2, _0x273756) { var _0x2b8676 = _0x5612de if (null == _0x478fa2) throw new TypeError(_0x2b8676(0x2cf)) for ( var _0x451cfb = Object(_0x478fa2), _0x5c5079 = -0xb5d + -0x15f0 + 0x214e; _0x5c5079 < arguments[_0x2b8676(0x259)]; _0x5c5079++ ) { var _0x3059a4 = arguments[_0x5c5079] if (null != _0x3059a4) { for (var _0x3ede90 in _0x3059a4) Object[_0x2b8676(0x344)][_0x2b8676(0x3b8)][_0x2b8676(0x334)](_0x3059a4, _0x3ede90) && (_0x451cfb[_0x3ede90] = _0x3059a4[_0x3ede90]) } } return _0x451cfb }, writable: !(0x3d * -0x43 + 0x2368 + -0x1371), configurable: !(0x12a + -0x1692 + 0x1568) }), Object[_0x5612de(0x17f)] || (Object['keys'] = ((_0x4d6c78 = Object[_0x5612de(0x344)][_0x5612de(0x3b8)]), (_0x312e19 = !{ toString: null }[_0x5612de(0x1da)]('toString')), (_0x2a32a1 = [ _0x5612de(0x3ae), _0x5612de(0x2c8), _0x5612de(0x303), _0x5612de(0x3b8), 'isPrototypeOf', _0x5612de(0x1da), 'constructor' ]), (_0x371ac2 = _0x2a32a1[_0x5612de(0x259)]), function (_0x457a19) { var _0x2d3152 = _0x5612de if (_0x2d3152(0x1ee) != typeof _0x457a19 && (_0x2d3152(0x17d) !== _0x1db123(_0x457a19) || null === _0x457a19)) throw new TypeError(_0x2d3152(0x374)) var _0x11aef0, _0x29131e, _0x4c2a63 = [] for (_0x11aef0 in _0x457a19) _0x4d6c78[_0x2d3152(0x334)](_0x457a19, _0x11aef0) && _0x4c2a63[_0x2d3152(0x36e)](_0x11aef0) if (_0x312e19) { for (_0x29131e = -0x2406 + -0x1209 + 0x1 * 0x360f; _0x29131e < _0x371ac2; _0x29131e++) _0x4d6c78['call'](_0x457a19, _0x2a32a1[_0x29131e]) && _0x4c2a63[_0x2d3152(0x36e)](_0x2a32a1[_0x29131e]) } return _0x4c2a63 })) var _0x45b94b = { __version__: _0x5612de(0x167), feVersion: 0x2, domNotValid: !(-0x1e27 + -0x3fa * -0x2 + 0x1634), refererKey: _0x5612de(0x318), pushVersion: _0x5612de(0x2ca), secInfoHeader: _0x5612de(0x248) } function _0x598972(_0x215b45, _0x2d7329) { var _0x401595 = _0x5612de if (_0x401595(0x33c) == typeof _0x2d7329) for ( var _0x5d92d9, _0x112fe4 = _0x215b45 + '=', _0x28aeed = _0x2d7329[_0x401595(0x342)](/[;&]/), _0x26307f = 0x11 * -0x97 + 0x126 * -0xd + -0x1 * -0x18f5; _0x26307f < _0x28aeed[_0x401595(0x259)]; _0x26307f++ ) { for (_0x5d92d9 = _0x28aeed[_0x26307f]; '\x20' === _0x5d92d9['charAt'](0x1589 + 0x5e4 + 0x7 * -0x3eb);) _0x5d92d9 = _0x5d92d9[_0x401595(0x1b0)](-0x16d9 + -0x1 * 0x99c + 0x2 * 0x103b, _0x5d92d9['length']) if (0x15cd + -0x1235 + 0x1 * -0x398 === _0x5d92d9[_0x401595(0x2c5)](_0x112fe4)) return _0x5d92d9[_0x401595(0x1b0)](_0x112fe4[_0x401595(0x259)], _0x5d92d9[_0x401595(0x259)]) } } function _0x24dc34(_0x3e96bb) { var _0x22cc3b = _0x5612de try { var _0xdacad4 = '' return (window['sessionStorage'] && (_0xdacad4 = window['sessionStorage'][_0x22cc3b(0x2d8)](_0x3e96bb))) || (window[_0x22cc3b(0x1dc)] && (_0xdacad4 = window[_0x22cc3b(0x1dc)][_0x22cc3b(0x2d8)](_0x3e96bb))) ? _0xdacad4 : (_0xdacad4 = _0x598972(_0x3e96bb, document['cookie'])) } catch (_0x195c1d) { return '' } } function _0x1f42cb(_0x247ee6, _0x28501b) { var _0xfed486 = _0x5612de try { window[_0xfed486(0x3be)] && window['sessionStorage']['setItem'](_0x247ee6, _0x28501b), window[_0xfed486(0x1dc)] && window[_0xfed486(0x1dc)][_0xfed486(0x1c4)](_0x247ee6, _0x28501b), ((document[_0xfed486(0x272)] = _0x247ee6 + _0xfed486(0x35e)), (document[_0xfed486(0x272)] = _0x247ee6 + '=' + _0x28501b + _0xfed486(0x1c1) + new Date(new Date()['getTime']() + (0x10 * 0x792317 + 0x37870478 + -0x2 * 0xd8658f4))[_0xfed486(0x15e)]() + _0xfed486(0x3c1))) } catch (_0x2bd822) { } } function _0x2ecc5a(_0x5893e4) { var _0x3a0d7f = _0x5612de try { window[_0x3a0d7f(0x3be)] && window['sessionStorage']['removeItem'](_0x5893e4), window[_0x3a0d7f(0x1dc)] && window[_0x3a0d7f(0x1dc)][_0x3a0d7f(0x2c3)](_0x5893e4), (document[_0x3a0d7f(0x272)] = _0x5893e4 + _0x3a0d7f(0x35e)) } catch (_0x2f5b70) { } } for ( var _0x462335 = { boe: !(0x1e0d + -0x1093 * 0x1 + -0xd79), aid: 0x0, dfp: !(-0x1 * 0x703 + 0x1025 + 0x29 * -0x39), sdi: !(0x49 * -0x77 + -0x6da * 0x2 + -0x4 * -0xbe9), enablePathList: [], _enablePathListRegex: [], urlRewriteRules: [], _urlRewriteRules: [], initialized: !(-0x31 * 0x3d + 0x9df + 0x1cf), enableTrack: !(0x89 * -0x1a + -0x21ca + 0x2fb5), track: { unitTime: 0x0, unitAmount: 0x0, fre: 0x0 }, triggerUnload: !(-0x3e5 * -0x5 + -0x23cb + 0x3 * 0x571), region: '', regionConf: {}, umode: 0x0, v: !(-0x1155 + -0x25d4 + -0x1 * -0x372a), _enableSignature: [], perf: !(0x1 * -0x1c2e + 0xef8 + -0xc7 * -0x11), xxbg: !(-0xf75 + 0x3 * 0x4e5 + 0x12 * 0xb) }, _0x3d40ff = { debug: function (_0x2cf151, _0x4acfb1) { var _0x1b6639 = _0x5612de _0x462335[_0x1b6639(0x1b6)] } }, _0x100715 = _0x5612de(0x2d7)[_0x5612de(0x342)](''), _0x1f510e = [], _0x37750d = [], _0x1cb307 = -0xe55 + 0x1c37 + 0x2 * -0x6f1; _0x1cb307 < 0x241b + 0x10 * -0xe6 + -0x1 * 0x14bb; _0x1cb307++ ) (_0x1f510e[_0x1cb307] = _0x100715[(_0x1cb307 >> (0xd03 + -0x269a + 0x1 * 0x199b)) & (0xa64 * 0x3 + -0xf7b + -0xfa2)] + _0x100715[(0x2bb + -0x3 * 0x92d + 0x18db) & _0x1cb307]), _0x1cb307 < -0x1 * -0x82 + 0x34 * -0x3b + -0x2 * -0x5c5 && (_0x1cb307 < 0x10f1 * 0x1 + 0x86a * 0x4 + -0x328f ? (_0x37750d[-0x2029 + -0x1ef1 + -0x3f4a * -0x1 + _0x1cb307] = _0x1cb307) : (_0x37750d[-0x2485 + 0x1d * 0x6d + 0x1883 + _0x1cb307] = _0x1cb307)) var _0x55de18 = function (_0x33a277) { var _0x5155ba = _0x5612de for (var _0x9eb2a1 = _0x33a277[_0x5155ba(0x259)], _0x1edfde = '', _0x2a69c4 = -0x1c39 + 0x569 + 0x16d0; _0x2a69c4 < _0x9eb2a1;) _0x1edfde += _0x1f510e[_0x33a277[_0x2a69c4++]] return _0x1edfde }, _0x655940 = function (_0x177456) { for ( var _0x1ffb9c = _0x177456['length'] >> (0x1 * 0x104b + 0x10b1 + -0x20fb), _0x3563ef = _0x1ffb9c << (-0x1 * -0x263 + -0x77 * -0x21 + 0xd * -0x15d), _0x22520c = new Uint8Array(_0x1ffb9c), _0x32553 = 0x345 * 0x9 + -0x1e9a + -0x1 * -0x12d, _0x11b847 = 0x1 * 0x623 + -0x239f * -0x1 + -0x29c2; _0x11b847 < _0x3563ef; ) _0x22520c[_0x32553++] = (_0x37750d[_0x177456['charCodeAt'](_0x11b847++)] << (-0x1551 + -0xb5a + 0x20af * 0x1)) | _0x37750d[_0x177456['charCodeAt'](_0x11b847++)] return _0x22520c }, _0x42e709 = { encode: _0x55de18, decode: _0x655940 }, _0x1e7721 = _0x5612de(0x384) != typeof globalThis ? globalThis : _0x5612de(0x384) != typeof window ? window : _0x5612de(0x384) != typeof global ? global : 'undefined' != typeof self ? self : {} function _0x3bc8d3(_0x14565d) { var _0x442e14 = _0x5612de return _0x14565d && _0x14565d[_0x442e14(0x3bd)] && Object[_0x442e14(0x344)][_0x442e14(0x3b8)][_0x442e14(0x334)](_0x14565d, _0x442e14(0x1d3)) ? _0x14565d[_0x442e14(0x1d3)] : _0x14565d } function _0x3abc0b(_0x1ca7bd) { var _0x292845 = _0x5612de return _0x1ca7bd && Object[_0x292845(0x344)]['hasOwnProperty'][_0x292845(0x334)](_0x1ca7bd, _0x292845(0x1d3)) ? _0x1ca7bd[_0x292845(0x1d3)] : _0x1ca7bd } function _0x41ace1(_0x2b7455) { var _0x39470d = _0x5612de return _0x2b7455 && Object[_0x39470d(0x344)][_0x39470d(0x3b8)]['call'](_0x2b7455, _0x39470d(0x1d3)) && 0x155 + 0x16f8 + -0x184c === Object[_0x39470d(0x17f)](_0x2b7455)[_0x39470d(0x259)] ? _0x2b7455[_0x39470d(0x1d3)] : _0x2b7455 } function _0x3e9554(_0x22797e) { var _0x1fa97f = _0x5612de if (_0x22797e[_0x1fa97f(0x3bd)]) return _0x22797e var _0x21d08f = Object[_0x1fa97f(0x175)]({}, _0x1fa97f(0x3bd), { value: !(0x1f82 + -0x10d * 0x1d + 0x5 * -0x35) }) return ( Object[_0x1fa97f(0x17f)](_0x22797e)['forEach'](function (_0x19f7e0) { var _0x1f5a81 = _0x1fa97f, _0x3cf185 = Object[_0x1f5a81(0x2a6)](_0x22797e, _0x19f7e0) Object['defineProperty']( _0x21d08f, _0x19f7e0, _0x3cf185[_0x1f5a81(0x32b)] ? _0x3cf185 : { enumerable: !(-0x222 * -0x8 + 0x1 * -0x21ac + 0x84e * 0x2), get: function () { return _0x22797e[_0x19f7e0] } } ) }), _0x21d08f ) } function _0x56409e(_0x362d96) { var _0x265452 = _0x5612de, _0x5870ef = { exports: {} } return _0x362d96(_0x5870ef, _0x5870ef[_0x265452(0x1b8)]), _0x5870ef['exports'] } function _0x171dc9(_0x5983b9) { var _0x32782f = _0x5612de throw new Error(_0x32782f(0x36d) + _0x5983b9 + _0x32782f(0x357)) } var _0x90795 = _0x56409e(function (_0xb9c7d1) { !(function () { var _0x2db296 = w_0x25f3, _0x1f977a = 'input\x20is\x20invalid\x20type', _0x5a87b4 = _0x2db296(0x17d) == typeof window, _0x11d177 = _0x5a87b4 ? window : {} _0x11d177[_0x2db296(0x37a)] && (_0x5a87b4 = !(-0x15c4 + 0x97d * -0x2 + 0xb7 * 0x39)) var _0x387fd8 = !_0x5a87b4 && _0x2db296(0x17d) == typeof self, _0x2e1226 = !_0x11d177[_0x2db296(0x216)] && _0x2db296(0x17d) == typeof process && process[_0x2db296(0x194)] && process[_0x2db296(0x194)][_0x2db296(0x287)] _0x2e1226 ? (_0x11d177 = _0x1e7721) : _0x387fd8 && (_0x11d177 = self) var _0x299a21 = !_0x11d177['JS_MD5_NO_COMMON_JS'] && _0xb9c7d1[_0x2db296(0x1b8)], _0x5efc8f = !(-0x8c4 + -0xc3a + -0x1 * -0x14ff), _0x1edc95 = !_0x11d177[_0x2db296(0x2e6)] && 'undefined' != typeof ArrayBuffer, _0x142491 = _0x2db296(0x2d7)[_0x2db296(0x342)](''), _0x146907 = [ 0x148 * 0x5 + -0x753 * 0x2 + -0x175 * -0x6, 0x1 * 0x340b + 0x460a + 0x1f9 * 0x3, 0x2766cb + -0x6327ac + 0x353 * 0x387b, -(-0xc13e2aae + -0x3aff8440 + 0x17c3daeee) ], _0x4d13bd = [ -0x1721 + -0x1 * 0x611 + 0x1d32, -0x390 + -0x3a5 * -0x3 + -0x757, 0x5fc + -0x64d * -0x2 + -0x1286, 0x278 + 0x3 * 0x105 + -0x56f ], _0x3f581b = [_0x2db296(0x352), _0x2db296(0x238), _0x2db296(0x19b), _0x2db296(0x275), 'arrayBuffer', _0x2db296(0x25f)], _0xcb4d61 = _0x2db296(0x315)[_0x2db296(0x342)](''), _0x5c5e45 = [], _0x54b265 if (_0x1edc95) { var _0x171107 = new ArrayBuffer(0xc87 + -0xcd8 + 0x95) ; (_0x54b265 = new Uint8Array(_0x171107)), (_0x5c5e45 = new Uint32Array(_0x171107)) } ; (!_0x11d177[_0x2db296(0x216)] && Array[_0x2db296(0x2af)]) || (Array['isArray'] = function (_0x263669) { var _0x1dd8cd = _0x2db296 return _0x1dd8cd(0x331) === Object['prototype']['toString']['call'](_0x263669) }), !_0x1edc95 || (!_0x11d177[_0x2db296(0x305)] && ArrayBuffer['isView']) || (ArrayBuffer['isView'] = function (_0x4d052f) { var _0x23ceed = _0x2db296 return ( _0x23ceed(0x17d) == typeof _0x4d052f && _0x4d052f[_0x23ceed(0x275)] && _0x4d052f['buffer'][_0x23ceed(0x2ac)] === ArrayBuffer ) }) var _0x2e393f = function (_0x55b71b) { return function (_0x6901ec) { var _0x38b178 = w_0x25f3 return new _0x22f902(!(0x191d + 0x9e + -0x19bb))[_0x38b178(0x2d5)](_0x6901ec)[_0x55b71b]() } }, _0x1edabb = function () { var _0x5664ca = _0x2db296, _0x4c275f = _0x2e393f(_0x5664ca(0x352)) _0x2e1226 && (_0x4c275f = _0x4d7e2d(_0x4c275f)), (_0x4c275f[_0x5664ca(0x3b7)] = function () { return new _0x22f902() }), (_0x4c275f['update'] = function (_0x5c3464) { return _0x4c275f['create']()['update'](_0x5c3464) }) for (var _0x349d5f = -0x9d * -0x1f + 0x1 * 0x230c + -0x15 * 0x293; _0x349d5f < _0x3f581b[_0x5664ca(0x259)]; ++_0x349d5f) { var _0x1537c4 = _0x3f581b[_0x349d5f] _0x4c275f[_0x1537c4] = _0x2e393f(_0x1537c4) } return _0x4c275f }, _0x4d7e2d = function (_0x1afe1b) { var _0x3e0a6e = eval('var _0x13db80 = w_0x25f3;require(_0x13db80(628));'), _0x5bfe7e = eval("var _0x20dc8b = w_0x25f3;require('buffer')[_0x20dc8b(424)];"), _0x3d7396 = function (_0x5142ff) { var _0x30639a = w_0x25f3 if (_0x30639a(0x33c) == typeof _0x5142ff) return _0x3e0a6e[_0x30639a(0x1ca)](_0x30639a(0x35c)) [_0x30639a(0x2d5)](_0x5142ff, _0x30639a(0x2a8)) [_0x30639a(0x19b)](_0x30639a(0x352)) if (null == _0x5142ff) throw _0x1f977a return ( _0x5142ff[_0x30639a(0x2ac)] === ArrayBuffer && (_0x5142ff = new Uint8Array(_0x5142ff)), Array[_0x30639a(0x2af)](_0x5142ff) || ArrayBuffer[_0x30639a(0x2c7)](_0x5142ff) || _0x5142ff[_0x30639a(0x2ac)] === _0x5bfe7e ? _0x3e0a6e[_0x30639a(0x1ca)](_0x30639a(0x35c)) ['update'](new _0x5bfe7e(_0x5142ff)) [_0x30639a(0x19b)](_0x30639a(0x352)) : _0x1afe1b(_0x5142ff) ) } return _0x3d7396 } function _0x22f902(_0xad0da7) { var _0x68ef08 = _0x2db296 if (_0xad0da7) (_0x5c5e45[-0x1b4c * 0x1 + -0x126b * 0x2 + 0x4022] = _0x5c5e45[0x143f + -0x2217 + 0xde8] = _0x5c5e45[0x16 * 0x2e + -0x1d7c + 0x1989] = _0x5c5e45[0xa0 * -0x26 + -0x3 * 0x93f + 0x337f * 0x1] = _0x5c5e45[-0xed2 + 0xe1d + 0x2e * 0x4] = _0x5c5e45[-0x10ff + -0x1 * -0x394 + 0xd6f] = _0x5c5e45[-0x36f * -0x2 + 0x1 * 0x1a5 + -0x87e] = _0x5c5e45[-0x1f81 * 0x1 + 0x25ce * -0x1 + -0x1 * -0x4555] = _0x5c5e45[0x1ae7 * 0x1 + 0x1 * -0xe3c + -0xca4 * 0x1] = _0x5c5e45[-0x583 * -0x4 + -0x5f7 * -0x5 + -0x33d7] = _0x5c5e45[0x25e + -0x1d4b * 0x1 + -0x3a * -0x77] = _0x5c5e45[0xef9 + -0x30 * -0x57 + -0x1f3f] = _0x5c5e45[0x11e + -0x18f * 0x7 + 0x9d6] = _0x5c5e45[-0x2521 * -0x1 + 0x1 * 0x1bf4 + 0x4109 * -0x1] = _0x5c5e45[0x19 * 0xa6 + 0x1f06 + -0x2f2f] = _0x5c5e45[-0x22d0 + 0x1f1 * 0xf + 0x5bf] = _0x5c5e45[0x7 * 0x549 + -0xa39 + 0x1 * -0x1ab7] = 0x1 * -0xfb + 0x1995 + 0xc4d * -0x2), (this['blocks'] = _0x5c5e45), (this[_0x68ef08(0x329)] = _0x54b265) else { if (_0x1edc95) { var _0x44d65b = new ArrayBuffer(0x11 * -0xb + 0xbfd + -0xafe) ; (this[_0x68ef08(0x329)] = new Uint8Array(_0x44d65b)), (this[_0x68ef08(0x319)] = new Uint32Array(_0x44d65b)) } else this[_0x68ef08(0x319)] = [ 0x45 * 0x10 + -0xd15 + 0x8c5, 0x1d70 + 0x493 + -0x2203 * 0x1, 0x46 * 0x86 + 0x8 * -0x14e + -0x1a34, 0x9bb + 0x25 * 0xdf + -0x29f6, -0x1c * -0xda + 0x188 + 0xcb * -0x20, -0x442 + -0x199a + 0x1ddc, -0x2 * -0x32d + -0x605 * -0x2 + -0x1264, 0x1af * -0x8 + -0xf3c + 0x29c * 0xb, -0x8cc + 0x1c3 + 0x709 * 0x1, 0xb53 * 0x1 + 0x18e6 + -0x3 * 0xc13, -0x2 * 0x135e + 0x444 + 0x2278, 0xe8 * 0x2b + 0x2106 + -0xa * 0x733, 0x3 * 0x449 + 0x1103 + -0x1dde, 0x30 + -0x3 * -0x95 + -0x1ef, 0x3ca * -0x3 + -0x9 * -0x1cb + -0x3 * 0x197, -0x14ce + -0x1b9 + 0x1687, -0xb2f + -0x53f * 0x3 + 0x1aec ] } ; (this['h0'] = this['h1'] = this['h2'] = this['h3'] = this[_0x68ef08(0x385)] = this[_0x68ef08(0x25b)] = this[_0x68ef08(0x1cd)] = -0x1 * 0x4f9 + 0xeb * -0xd + 0x10e8), (this[_0x68ef08(0x182)] = this[_0x68ef08(0x1e9)] = !(-0x983 + -0x5b1 * -0x1 + 0x3d3)), (this[_0x68ef08(0x19f)] = !(-0xcdf + 0x2157 + -0x1478)) } ; (_0x22f902[_0x2db296(0x344)][_0x2db296(0x2d5)] = function (_0x36f09d) { var _0x449340 = _0x2db296 if (!this['finalized']) { var _0x462898, _0x1dd68e = typeof _0x36f09d if (_0x449340(0x33c) !== _0x1dd68e) { if ('object' !== _0x1dd68e) throw _0x1f977a if (null === _0x36f09d) throw _0x1f977a if (_0x1edc95 && _0x36f09d['constructor'] === ArrayBuffer) _0x36f09d = new Uint8Array(_0x36f09d) else { if (!(Array[_0x449340(0x2af)](_0x36f09d) || (_0x1edc95 && ArrayBuffer['isView'](_0x36f09d)))) throw _0x1f977a } _0x462898 = !(-0xfea + 0x449 * 0x3 + -0x1 * -0x30f) } for ( var _0x2c6513, _0x1fd15b, _0x432ef6 = 0xadd + -0x4d7 * 0x2 + 0x1 * -0x12f, _0x383058 = _0x36f09d[_0x449340(0x259)], _0x17a6ed = this[_0x449340(0x319)], _0x161a31 = this[_0x449340(0x329)]; _0x432ef6 < _0x383058; ) { if ( (this[_0x449340(0x1e9)] && ((this[_0x449340(0x1e9)] = !(-0x657 + 0x4fb + -0x15d * -0x1)), (_0x17a6ed[0x22e1 * -0x1 + -0xeb2 + 0x3193] = _0x17a6ed[0x283 * -0xd + -0x141e + 0x34d5]), (_0x17a6ed[0x1af3 * 0x1 + -0x14d1 * 0x1 + -0x15 * 0x4a] = _0x17a6ed[-0xc3 * -0x2f + -0x49 * -0x31 + 0x3 * -0x1097] = _0x17a6ed[0x1e34 + -0x1 * -0x1837 + -0x3669] = _0x17a6ed[-0x12e3 + -0x1733 * -0x1 + 0x1 * -0x44d] = _0x17a6ed[0x31 * -0x8b + 0x1643 * 0x1 + 0x45c] = _0x17a6ed[0x87 * -0xd + -0x14d5 + 0x1bb5] = _0x17a6ed[0x1d70 + 0x255a + 0x4 * -0x10b1] = _0x17a6ed[0x1312 + 0x2e6 + 0x15f1 * -0x1] = _0x17a6ed[0x1ed9 + 0x551 * -0x1 + -0x1980] = _0x17a6ed[0x269 * -0x7 + 0x1d8 + 0xf10] = _0x17a6ed[0x1134 + -0x1 * -0x15cd + -0xcfd * 0x3] = _0x17a6ed[0x1229 * 0x1 + 0x23 * -0xe3 + 0xceb] = _0x17a6ed[0x15 * 0x13a + -0x23e3 * 0x1 + 0x1 * 0xa2d] = _0x17a6ed[-0x4 * 0x8ee + -0x1d7d + 0x4142 * 0x1] = _0x17a6ed[0x9d9 + 0x1 * -0x215b + 0x34 * 0x74] = _0x17a6ed[0x1e72 + -0x9 * 0x2b + 0xa8 * -0x2c] = 0x857 + 0x1cef + -0x2546)), _0x462898) ) { if (_0x1edc95) { for ( _0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < -0x836 + 0x1150 + -0xce * 0xb; ++_0x432ef6 ) _0x161a31[_0x1fd15b++] = _0x36f09d[_0x432ef6] } else { for ( _0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < -0x4 * -0x4e8 + -0xedb * 0x1 + -0x485; ++_0x432ef6 ) _0x17a6ed[_0x1fd15b >> (0x11 * 0x5c + 0x1378 * -0x2 + 0x3 * 0xaf2)] |= _0x36f09d[_0x432ef6] << _0x4d13bd[(0x1 * -0x4f + -0x2036 + -0x1044 * -0x2) & _0x1fd15b++] } } else { if (_0x1edc95) { for ( _0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < 0xc4 * -0x1 + 0x78f * -0x1 + 0x893; ++_0x432ef6 ) (_0x2c6513 = _0x36f09d[_0x449340(0x195)](_0x432ef6)) < 0xd * 0x1a + 0x8f + -0x161 ? (_0x161a31[_0x1fd15b++] = _0x2c6513) : _0x2c6513 < 0x1b9a + 0x1 * -0x4a9 + 0xef1 * -0x1 ? ((_0x161a31[_0x1fd15b++] = (-0x1aaa * -0x1 + 0x2511 * -0x1 + -0x23b * -0x5) | (_0x2c6513 >> (0x1568 + 0x75a * 0x1 + -0x994 * 0x3))), (_0x161a31[_0x1fd15b++] = (0x54a + -0x1 * 0x1a66 + -0x1cd * -0xc) | ((0x8ad * 0x4 + 0x6a3 * 0x1 + -0x2918) & _0x2c6513))) : _0x2c6513 < 0x1807f + -0x1 * -0x44d4 + 0xed53 * -0x1 || _0x2c6513 >= -0x1 * -0x123e4 + 0x1be31 + -0x5 * 0x66d1 ? ((_0x161a31[_0x1fd15b++] = (0x1 * 0x11f + 0xffd * -0x1 + 0xfbe) | (_0x2c6513 >> (0x1 * 0x65 + 0x533 + -0x11c * 0x5))), (_0x161a31[_0x1fd15b++] = (0x4 * 0x72b + 0x23c9 * 0x1 + -0x3ff5) | ((_0x2c6513 >> (0x9 * 0x9 + 0x5 * 0x517 + -0x5 * 0x526)) & (0x200b + 0x1 * 0xbe7 + -0x2bb3))), (_0x161a31[_0x1fd15b++] = (0x1 * 0x128f + 0x11 * -0x6a + -0xb05) | ((0x27 * 0x59 + -0x2126 + 0x1 * 0x13d6) & _0x2c6513))) : ((_0x2c6513 = -0xb295 + 0x185 * 0x139 + -0x2908 + ((((-0x1ec2 * -0x1 + -0x183e + -0xf * 0x2b) & _0x2c6513) << (0x2e * 0x3 + 0x14b + 0x1 * -0x1cb)) | ((0x1225 * 0x1 + 0x2376 + -0x319c) & _0x36f09d[_0x449340(0x195)](++_0x432ef6)))), (_0x161a31[_0x1fd15b++] = (-0x969 + 0xc97 + -0x23e) | (_0x2c6513 >> (-0xc19 + -0x14f9 + 0x2124))), (_0x161a31[_0x1fd15b++] = (0x202 + 0x1 * 0x187 + -0x309) | ((_0x2c6513 >> (-0x1da3 + -0xa * 0xda + -0x379 * -0xb)) & (0x2 * -0x117b + -0x7c9 + 0x2afe))), (_0x161a31[_0x1fd15b++] = (0x1 * -0x1043 + 0x1185 + -0xc2) | ((_0x2c6513 >> (-0x8c6 + 0x1d87 + -0x1d * 0xb7)) & (0x2a * 0xe7 + -0x1 * 0x1869 + -0xd3e))), (_0x161a31[_0x1fd15b++] = (-0x58e + 0x6 * -0x216 + 0x949 * 0x2) | ((0x2474 * -0x1 + 0xa9 * 0xd + 0x1c1e) & _0x2c6513))) } else { for ( _0x1fd15b = this[_0x449340(0x385)]; _0x432ef6 < _0x383058 && _0x1fd15b < -0x48a * 0x7 + 0x1993 + -0xd * -0x7f; ++_0x432ef6 ) (_0x2c6513 = _0x36f09d[_0x449340(0x195)](_0x432ef6)) < 0x2 * -0x86 + 0x101 * 0x1f + -0x1 * 0x1d93 ? (_0x17a6ed[_0x1fd15b >> (-0x1297 + 0x71a + 0xb7f)] |= _0x2c6513 << _0x4d13bd[(-0x1f26 + 0xd17 + 0x1212) & _0x1fd15b++]) : _0x2c6513 < 0x11b7 + -0x150d + 0xb56 ? ((_0x17a6ed[_0x1fd15b >> (-0x231f + -0x8eb + 0x2c0c)] |= ((0x1ae0 + 0x70b + -0x212b) | (_0x2c6513 >> (-0x87f + -0x23f * 0x5 + -0x13c * -0x10))) << _0x4d13bd[(0x3fb + 0x8e1 * -0x1 + 0x4e9) & _0x1fd15b++]), (_0x17a6ed[_0x1fd15b >> (-0x1d97 + 0x6ad + 0x16ec)] |= ((0x1d0e + 0xf0a + -0x2b98) | ((0xf2c + 0xbb * -0x20 + 0x873) & _0x2c6513)) << _0x4d13bd[(0x8d9 + -0x17e0 + 0xf0a) & _0x1fd15b++])) : _0x2c6513 < -0x8b7d + 0x113bf + 0x4fbe || _0x2c6513 >= -0xc9c0 + 0x16d4a * 0x1 + 0x3c76 ? ((_0x17a6ed[_0x1fd15b >> (0x2 * 0x74f + 0x1533 + -0x23cf)] |= ((-0x7 * 0x28 + -0x2 * -0x1bb + -0x17e) | (_0x2c6513 >> (0x1d5c + 0x1e6c + -0x1 * 0x3bbc))) << _0x4d13bd[(0x12 * 0x119 + 0x4 * -0x1c6 + -0xca7) & _0x1fd15b++]), (_0x17a6ed[_0x1fd15b >> (-0x26 * 0x2e + -0x12aa * 0x2 + -0x2c2a * -0x1)] |= ((0x245a + -0x1aa1 + -0x1 * 0x939) | ((_0x2c6513 >> (0x1fa6 + -0x735 + -0x2f * 0x85)) & (-0x5d3 + -0x1eb2 * -0x1 + -0x18a0))) << _0x4d13bd[(0xa40 + 0x1f49 + -0x84e * 0x5) & _0x1fd15b++]), (_0x17a6ed[_0x1fd15b >> (0x21 * -0xa4 + -0x139 * -0x5 + 0x1 * 0xf09)] |= ((-0x1434 + 0x5 * -0x35 + 0x15bd) | ((-0xc2d + 0x2655 + 0x25b * -0xb) & _0x2c6513)) << _0x4d13bd[(0x76 * 0x26 + -0x1 * 0x8ad + 0x1c4 * -0x5) & _0x1fd15b++])) : ((_0x2c6513 = 0x12e * -0xbf + 0x1cc8a + 0x8c * 0x26 + ((((-0x3f5 * 0x3 + -0xfe8 + 0x1fc6) & _0x2c6513) << (0x29a + 0x13a9 + -0x1639)) | ((0x1 * -0x1dd7 + 0x6a5 + 0x1 * 0x1b31) & _0x36f09d[_0x449340(0x195)](++_0x432ef6)))), (_0x17a6ed[_0x1fd15b >> (0xd * 0x61 + 0xcb * -0x1e + 0x12df)] |= ((0x1 * -0xee4 + 0x2 * -0x767 + -0x6 * -0x51b) | (_0x2c6513 >> (0x1 * 0x1a4d + -0x3 * 0x149 + -0x1660))) << _0x4d13bd[(-0x1c70 + -0x1 * -0x57b + 0x1 * 0x16f8) & _0x1fd15b++]), (_0x17a6ed[_0x1fd15b >> (0xef1 + -0xba0 + -0x1 * 0x34f)] |= ((-0xa3 * -0x3 + 0x26af + 0x140c * -0x2) | ((_0x2c6513 >> (-0x518 + 0x1 * -0xc26 + 0x114a)) & (-0x25 * -0xd1 + -0x1130 * -0x1 + -0x2f26))) << _0x4d13bd[(-0x73 * -0xb + -0x17d * 0x1 + 0x1 * -0x371) & _0x1fd15b++]), (_0x17a6ed[_0x1fd15b >> (0x3 * -0x107 + 0x1dbd + -0x1aa6)] |= ((-0x151c + 0x16 * -0x191 + 0x3812) | ((_0x2c6513 >> (0xded * -0x1 + 0x45 + 0xdae)) & (-0x2af * -0x7 + -0x49 + 0x1241 * -0x1))) << _0x4d13bd[(-0x19a2 + -0x7d2 + 0x2177) & _0x1fd15b++]), (_0x17a6ed[_0x1fd15b >> (-0x180e + 0x13d2 + -0x1 * -0x43e)] |= ((-0x9 * -0x1f5 + -0xf1 * 0xd + -0x6 * 0xd0) | ((0x7f * 0x2f + 0x1 * 0x188c + -0x986 * 0x5) & _0x2c6513)) << _0x4d13bd[(0x1cf9 + 0xb * -0xe7 + -0x1309) & _0x1fd15b++])) } } ; (this['lastByteIndex'] = _0x1fd15b), (this[_0x449340(0x25b)] += _0x1fd15b - this['start']), _0x1fd15b >= -0xa42 + 0x2 * -0x11c3 + 0x2e08 ? ((this[_0x449340(0x385)] = _0x1fd15b - (-0x2b * 0xe2 + 0xa55 + 0xd * 0x225)), this[_0x449340(0x2ba)](), (this[_0x449340(0x1e9)] = !(0xc54 + -0x1 * -0xfa3 + -0x1 * 0x1bf7))) : (this[_0x449340(0x385)] = _0x1fd15b) } return ( this[_0x449340(0x25b)] > -0x14462193f + -0xd7facb0 + -0x2 * -0x128f0e2f7 && ((this['hBytes'] += (this['bytes'] / (0x73e4b4e0 * 0x3 + -0x3fc * -0x40b5a1 + -0x486a * 0x4d396)) << (-0x1fbb * 0x1 + -0x1623 + 0x35de)), (this[_0x449340(0x25b)] = this[_0x449340(0x25b)] % (0x7d756c * -0x1e1 + -0x3b6aede * -0x2 + 0x278 * 0xc42bda))), this ) } }), (_0x22f902[_0x2db296(0x344)][_0x2db296(0x1d9)] = function () { var _0x8b694 = _0x2db296 if (!this[_0x8b694(0x182)]) { this[_0x8b694(0x182)] = !(0x1038 + 0x1 * -0x247f + 0x1d * 0xb3) var _0x52f24a = this[_0x8b694(0x319)], _0x21cbd8 = this[_0x8b694(0x32e)] ; (_0x52f24a[_0x21cbd8 >> (0x4cd * 0x4 + -0x1 * -0x1511 + -0x2843)] |= _0x146907[(0xb2e + -0x10 * -0xbf + -0x41 * 0x5b) & _0x21cbd8]), _0x21cbd8 >= 0x8fe * 0x3 + -0x231c + -0x42d * -0x2 && (this['hashed'] || this['hash'](), (_0x52f24a[0x666 + 0x1432 + -0x1a98] = _0x52f24a[0x24cd + 0x1e1 * 0x14 + 0x19 * -0x2f9]), (_0x52f24a[-0x1f46 + 0x1 * 0x1015 + 0xf41] = _0x52f24a[0xbe8 + 0x1a96 + 0xa7 * -0x3b] = _0x52f24a[-0xb * 0x14d + -0x1 * 0x59 + -0xeaa * -0x1] = _0x52f24a[-0x1f1 * -0x3 + -0x1d69 + 0x1799] = _0x52f24a[0xa7b * -0x2 + 0xbb1 * -0x1 + -0x20ab * -0x1] = _0x52f24a[-0x11dc + -0xaa + 0x2f * 0x65] = _0x52f24a[-0x1 * 0x1f99 + -0x1e53 * 0x1 + 0x3df2] = _0x52f24a[-0x103 * -0x5 + -0x2451 + 0x1f49] = _0x52f24a[0x21e6 + -0xf9 * 0x1 + -0x1 * 0x20e5] = _0x52f24a[0x88a + -0x1bea + -0x1 * -0x1369] = _0x52f24a[0xf4d + -0x177d * -0x1 + -0x26c0] = _0x52f24a[0x1e22 + 0x655 * 0x3 + -0x3116] = _0x52f24a[-0x196b + 0x19b * -0x10 + -0x2d * -0x123] = _0x52f24a[-0x1 * -0x228d + 0x1cfc + -0x3f7c] = _0x52f24a[-0x13b4 + -0x5bc + 0x197e] = _0x52f24a[0x1e68 + 0x1209 + -0x3062] = 0x26a1 + -0x124 * -0x20 + -0x4b21)), (_0x52f24a[0xbb3 + 0x1210 + -0x1db5] = this[_0x8b694(0x25b)] << (-0x15 * -0x1d7 + 0x2 * -0xc2a + -0xe4c)), (_0x52f24a[-0x19e2 + 0x28 * 0x55 + 0xca9] = (this[_0x8b694(0x1cd)] << (-0x178 * 0x6 + 0xa67 + 0x194 * -0x1)) | (this[_0x8b694(0x25b)] >>> (0x1a65 + -0x18 * 0x44 + -0x16c * 0xe))), this['hash']() } }), (_0x22f902[_0x2db296(0x344)][_0x2db296(0x2ba)] = function () { var _0x2f0149 = _0x2db296, _0x227f23, _0x3952af, _0x2a0c94, _0x39eb64, _0x2fd641, _0x113678, _0x128d32 = this[_0x2f0149(0x319)] this['first'] ? (_0x3952af = ((((_0x3952af = ((_0x227f23 = ((((_0x227f23 = _0x128d32[0xe * 0xd4 + 0x18b * -0x13 + 0x11b9] - (0x1ffe472d + -0x1 * 0x229b4beb + 0x8a3acdb * 0x5)) << (-0xe3 + 0x794 * 0x5 + 0x2 * -0x127d)) | (_0x227f23 >>> (-0x2125 + 0x21d4 + -0x96))) - (-0xa42713c + -0x131 * -0xc4faf + 0xbc9d634)) << (-0x76 + -0x13ee + 0x1464)) ^ ((_0x2a0c94 = ((((_0x2a0c94 = (-(0x1d99 * -0x236f + 0xdf * -0x44be3 + 0x18092f8b) ^ ((_0x39eb64 = ((((_0x39eb64 = (-(-0xfc * -0xaf0303 + 0x524d2f32 + -0xcedcd * 0xbb4) ^ ((0x1 * 0x7b470ebd + 0x1 * 0x4d64e86c + -0x51347fb2) & _0x227f23)) + _0x128d32[-0x2684 + 0x1f4e * -0x1 + 0x8f * 0x7d] - (0x563f0e * -0x16 + 0x59003ae + 0x46faddd * 0x2)) << (-0x684 + 0xa * 0x289 + -0x1a * 0xb9)) | (_0x39eb64 >>> (-0x1116 * -0x2 + 0xee9 * -0x1 + -0x132f * 0x1))) + _0x227f23) << (-0x2687 * -0x1 + 0xfe3 + -0x1 * 0x366a)) & (-(0x1a9157f + 0x1e0df645 + -0xf84b74d) ^ _0x227f23))) + _0x128d32[0x144d + 0x15b * -0x18 + 0xc3d] - (-0x1 * 0x5504eeba + 0x76f3f96f * 0x1 + -0x2 * -0x109ad3b9)) << (0x1af4 + -0x12cb + -0x818)) | (_0x2a0c94 >>> (0x7aa * 0x1 + -0x1994 * -0x1 + -0x212f))) + _0x39eb64) << (-0x9fc + -0x14 * 0xfa + -0x1d84 * -0x1)) & (_0x39eb64 ^ _0x227f23))) + _0x128d32[-0x2a * 0x97 + 0x18c8 + 0x1 * 0x1] - (-0x992 * 0x9361 + 0x23b1c4 + 0x1 * 0x53d34a17)) << (-0x7 * 0x1b1 + -0x234d + -0x136 * -0x27)) | (_0x3952af >>> (-0x113f * 0x1 + 0x5 * -0x7f + 0x1cc * 0xb))) + _0x2a0c94) << (-0x4f0 + -0x1 * -0x1f3d + -0x1a4d)) : ((_0x227f23 = this['h0']), (_0x3952af = this['h1']), (_0x2a0c94 = this['h2']), (_0x3952af = ((((_0x3952af += ((_0x227f23 = ((((_0x227f23 += ((_0x39eb64 = this['h3']) ^ (_0x3952af & (_0x2a0c94 ^ _0x39eb64))) + _0x128d32[0x3a5 + -0x1684 + 0x12df * 0x1] - (0x2b26bdc2 + -0x1 * -0x4468952b + -0x5773 * 0xcfc7)) << (-0x1805 + -0x18cb + 0x30d7)) | (_0x227f23 >>> (0x21ec * -0x1 + -0x53c * -0x1 + 0x1cc9))) + _0x3952af) << (0xfe0 + 0x16a4 + -0x2684)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x3952af ^ ((_0x39eb64 = ((((_0x39eb64 += (_0x2a0c94 ^ (_0x227f23 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[0x1 * -0x480 + 0x1 * 0x112f + -0xcae] - (0x1e4d0bcf + 0x1be * -0xbfe2b + 0xdd00bc5)) << (-0x26fe + -0x462 + 0x2b6c)) | (_0x39eb64 >>> (-0x1 * 0x251 + -0xd16 + 0xf7b))) + _0x227f23) << (0x15be * 0x1 + 0x2e3 * 0x8 + -0x2cd6)) & (_0x227f23 ^ _0x3952af))) + _0x128d32[-0xa5 * -0x1d + 0x5 * -0x105 + 0x2f * -0x4a] + (0x15 * 0x27c2519 + -0x1cb83878 + 0x654cf23 * 0x2)) << (-0x9d5 + -0x221e + -0xeac * -0x3)) | (_0x2a0c94 >>> (-0x718 * 0x2 + -0x5 * -0x556 + -0x425 * 0x3))) + _0x39eb64) << (0x223 * -0xb + -0x92 * 0x22 + 0x2ae5)) & (_0x39eb64 ^ _0x227f23))) + _0x128d32[-0x141c + 0x376 + 0x10a9] - (0x29f06346 + 0x14e90f87 * -0x3 + -0x3 * -0x1baefecb)) << (0x103a + -0x24f4 + 0x14d0)) | (_0x3952af >>> (-0x16a5 + -0xe92 + 0xbb * 0x33))) + _0x2a0c94) << (0x25a2 * 0x1 + 0x1a76 + -0x4018 * 0x1))), (_0x3952af = ((((_0x3952af += ((_0x227f23 = ((((_0x227f23 += (_0x39eb64 ^ (_0x3952af & (_0x2a0c94 ^ _0x39eb64))) + _0x128d32[-0x2552 + 0x577 + 0x1fdf] - (-0xec5a4e1 + 0x23fe4 * -0x78c + -0x9e * -0x447abf)) << (-0x46e + 0x19b5 + -0x8 * 0x2a8)) | (_0x227f23 >>> (0x100e + 0xd63 + -0x1d58))) + _0x3952af) << (-0x237d + 0x1955 * -0x1 + 0x3cd2)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x3952af ^ ((_0x39eb64 = ((((_0x39eb64 += (_0x2a0c94 ^ (_0x227f23 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[-0x203 + 0xd54 + -0x2d3 * 0x4] + (0x1 * -0x20e3c675 + 0x8ef8e325 + 0x4e53fd * -0x7e)) << (-0x9e3 * 0x2 + 0x2 * -0x8fd + 0x25cc)) | (_0x39eb64 >>> (-0x7bd + 0x2 * -0x844 + 0x1859 * 0x1))) + _0x227f23) << (-0x3dc + -0x122e + 0x326 * 0x7)) & (_0x227f23 ^ _0x3952af))) + _0x128d32[-0xbfd + -0x1 * 0xba3 + 0x17a6] - (-0x93f8bbe0 + -0x43dcbb55 + 0x1 * 0x12fa53122)) << (0x185 * -0x10 + -0x76c + 0x1fcd)) | (_0x2a0c94 >>> (0x19b + 0x51 * 0x6d + 0x171 * -0x19))) + _0x39eb64) << (0x971 + 0x1958 + -0x5 * 0x6f5)) & (_0x39eb64 ^ _0x227f23))) + _0x128d32[-0x978 * -0x3 + 0x315 + -0x2 * 0xfbb] - (-0x99026a + 0xa6ba6 * 0x47 + 0xc4927 * 0x9)) << (0x212 + 0x1 * 0x4c3 + 0xb * -0x9d)) | (_0x3952af >>> (-0x152a + 0x1 * -0x17b4 + -0x77c * -0x6))) + _0x2a0c94) << (-0xa7 * 0x1f + 0x2379 + -0xf40)), (_0x3952af = ((((_0x3952af += ((_0x227f23 = ((((_0x227f23 += (_0x39eb64 ^ (_0x3952af & (_0x2a0c94 ^ _0x39eb64))) + _0x128d32[-0x251a + -0x14 * -0x18d + 0x61e] + (0xb19f3051 + -0xb487bda1 * 0x1 + 0x6c692628)) << (0x1cc + -0x171a + 0x1555)) | (_0x227f23 >>> (0x1 * -0x223b + -0x282 + 0x24d6))) + _0x3952af) << (0x1453 + 0x1aee + -0x2f41)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x3952af ^ ((_0x39eb64 = ((((_0x39eb64 += (_0x2a0c94 ^ (_0x227f23 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[-0x1c63 + -0x1a88 + 0x36f4] - (0x334017ba + 0x1 * -0x90d7af8d + -0x86 * -0x191cf86)) << (-0x1db2 + 0x1 * 0x10b1 + 0xd0d)) | (_0x39eb64 >>> (-0x4 * -0x20 + -0xd81 * -0x1 + -0xded))) + _0x227f23) << (-0x2b0 + 0x4 * -0x5b0 + -0x94 * -0x2c)) & (_0x227f23 ^ _0x3952af))) + _0x128d32[-0x1 * -0xf25 + 0xe75 * 0x1 + -0x1d90] - (-0x5 * 0x4eb + 0x12ff3 * -0x1 + 0x1 * 0x1ecd9)) << (-0xa43 + 0x1eed + 0x1 * -0x1499)) | (_0x2a0c94 >>> (-0x1878 + -0x92b + 0x21b2))) + _0x39eb64) << (-0x1 * 0x2515 + -0x8c8 + -0x3b * -0xc7)) & (_0x39eb64 ^ _0x227f23))) + _0x128d32[0x80b * -0x4 + 0xff5 + 0x1042] - (-0x2d479161 * 0x5 + -0x139 * 0x33685d + 0x197e398dc)) << (-0x178 + -0x22bf + 0x1 * 0x244d)) | (_0x3952af >>> (0x15cc + -0x26b6 + -0x5 * -0x364))) + _0x2a0c94) << (0x293 * -0x2 + 0x18f7 + -0x13d1)), (_0x3952af = ((((_0x3952af += ((_0x227f23 = ((((_0x227f23 += (_0x39eb64 ^ (_0x3952af & (_0x2a0c94 ^ _0x39eb64))) + _0x128d32[-0x1225 + -0xa * -0x348 + 0x13 * -0xc5] + (-0x36f3e05c + 0x4445538c + 0x5e3e9df2)) << (-0x1b3 * -0x3 + 0x2702 + -0x2c14)) | (_0x227f23 >>> (-0x2 * 0x1006 + 0x25 * 0xc5 + 0x3ac))) + _0x3952af) << (0x2501 + 0x18fb + 0xf7f * -0x4)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x3952af ^ ((_0x39eb64 = ((((_0x39eb64 += (_0x2a0c94 ^ (_0x227f23 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[-0x13cb + -0xcd4 + 0x20ac] - (-0x24 * 0x1e9ae6 + -0xa0ba1 * 0x72 + -0x18cc1 * -0x737)) << (0x702 + 0x2b * -0x35 + 0x1f1)) | (_0x39eb64 >>> (-0x15dd + -0x22eb * -0x1 + 0x1 * -0xcfa))) + _0x227f23) << (0x224b * 0x1 + 0x2f * 0x33 + 0x4 * -0xaea)) & (_0x227f23 ^ _0x3952af))) + _0x128d32[0xec7 * -0x1 + -0x61 * -0x25 + 0xd0] - (0x48e87164 + 0x613cb841 + -0x509e6d33)) << (-0x1c0d + 0x5d0 + 0x164e)) | (_0x2a0c94 >>> (0x156a * 0x1 + 0x16e7 + -0x2c42))) + _0x39eb64) << (-0x1 * -0x19ec + 0x8b4 + -0x22a0)) & (_0x39eb64 ^ _0x227f23))) + _0x128d32[0x1df0 + -0x2365 + -0x1 * -0x584] + (0x34eb7 * 0x25f0 + -0x3 * -0x1a616a08 + -0x82ea7487)) << (-0x3 * 0xc8c + 0x1fc2 * -0x1 + -0x457c * -0x1)) | (_0x3952af >>> (-0x2464 + 0x2705 + -0xdd * 0x3))) + _0x2a0c94) << (-0x504 + 0x2 * -0x5f9 + 0x10f6)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ (_0x2a0c94 & ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x39eb64 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[0x1b4d + 0x2d4 * 0x5 + -0x2970] - (0x30139 * 0x8d + -0x738f7c2 + -0x1 * -0xf7325fb)) << (0x1acc + -0x13e5 + -0x6e2)) | (_0x227f23 >>> (0x7 * 0x1 + -0x10e9 + 0x10fd * 0x1))) + _0x3952af) << (-0x18fd + 0x10cc + 0x831)) ^ _0x3952af))) + _0x128d32[0x2 * 0x131e + -0x2511 + 0x1 * -0x125] - (-0x1f * -0x3953eea + -0x4 * -0x12786c0f + -0x793501d2)) << (0x210d + 0x11 * -0x241 + 0x54d * 0x1)) | (_0x39eb64 >>> (-0x4 * -0x265 + -0x292 + 0xfd * -0x7))) + _0x227f23) << (-0x200b + -0xa * 0xff + -0x1 * -0x2a01)) ^ (_0x227f23 & ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x3952af & (_0x39eb64 ^ _0x227f23))) + _0x128d32[-0x92 * -0x13 + 0x6b0 + -0x117b] + (-0x4be8e758 + -0x1a3c * -0x1e38f + 0x40b96625)) << (-0x1 * 0x13d1 + 0x22da + -0xefb)) | (_0x2a0c94 >>> (0x166d + -0x955 + -0xd06))) + _0x39eb64) << (-0x13af * 0x1 + -0x1 * -0x1307 + 0xa8)) ^ _0x39eb64))) + _0x128d32[-0x547 + -0x1 * 0x1c0b + -0x2152 * -0x1] - (0x7 * 0x14d828a + 0x7d4a6f4 + -0x3 * -0x1c75534)) << (0x1bb9 * -0x1 + -0x26ee + 0x42bb * 0x1)) | (_0x3952af >>> (0x8 * 0x296 + 0x1ce9 * 0x1 + -0x318d))) + _0x2a0c94) << (0x897 * 0x4 + 0x2ca + 0x3 * -0xc62)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ (_0x2a0c94 & ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x39eb64 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[0x107f * -0x1 + -0x1299 + -0x59 * -0x65] - (0x1079c263 + -0x1889 * -0x11026 + -0xbe0716)) << (-0x260c + -0x1c23 + 0x2 * 0x211a)) | (_0x227f23 >>> (0x22b * 0x1 + -0x16f3 + -0x14e3 * -0x1))) + _0x3952af) << (0x183b + -0x5 * -0x72a + -0x3c0d * 0x1)) ^ _0x3952af))) + _0x128d32[0x4 * 0x86b + 0x1064 + -0x3206] + (-0x1177f56 + -0x27de7f4 + -0x540d * -0x11d1)) << (0x167 * 0x5 + -0x5 * 0x531 + 0x12fb * 0x1)) | (_0x39eb64 >>> (0x244b + -0x13 * 0x139 + -0x9 * 0x171))) + _0x227f23) << (-0xf6d + -0x1f9e + 0x2f0b * 0x1)) ^ (_0x227f23 & ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x3952af & (_0x39eb64 ^ _0x227f23))) + _0x128d32[0x187 * 0x4 + 0x1e69 + -0x2476] - (-0x10191ede + -0xd72a9b7 + 0x44e9e214)) << (0x90 * 0xc + -0x2 * 0x12 + -0x68e)) | (_0x2a0c94 >>> (0x16 * 0x1c5 + 0x137b + 0x1d * -0x203))) + _0x39eb64) << (-0x14fa + 0x43 * -0x74 + -0x3356 * -0x1)) ^ _0x39eb64))) + _0x128d32[-0xf4a + -0x1992 + 0x4 * 0xa38] - (-0xae6496c + 0x21ece5a8 + 0x12567fc)) << (0x1ac8 + -0x1ed2 + 0x3e * 0x11)) | (_0x3952af >>> (0x1268 + 0x100d + 0x1 * -0x2269))) + _0x2a0c94) << (0x1817 * -0x1 + 0x239b + -0xb84 * 0x1)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ (_0x2a0c94 & ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x39eb64 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[0x5 * 0x19c + 0xef3 + -0x16f6] + (0x39d62e7 + 0xb397e9b + 0x130aec64)) << (0x11 * 0x21f + -0x1c66 + -0x7a4)) | (_0x227f23 >>> (-0xf86 + 0x2 * -0x4e5 + 0x879 * 0x3))) + _0x3952af) << (0x258a + 0x19ec + -0x3f76)) ^ _0x3952af))) + _0x128d32[0x914 + 0xd73 + 0x20b * -0xb] - (-0xab52d21 + -0x845d9 * 0x1f7 + 0x57bf62aa)) << (-0x1 * 0x2f + -0x1280 + 0x12b8)) | (_0x39eb64 >>> (0x2e * -0x9 + 0x85 * 0x4b + -0x2542))) + _0x227f23) << (-0x151 * 0x9 + 0x20da + -0x1501)) ^ (_0x227f23 & ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x3952af & (_0x39eb64 ^ _0x227f23))) + _0x128d32[-0x84 * 0x39 + 0x57f + 0x2fd * 0x8] - (0x852a967 + 0xa4943f2 + -0x770fae0)) << (-0x5 * -0x722 + 0x1 * -0x155f + -0xe3d)) | (_0x2a0c94 >>> (0x171b + -0x2709 * 0x1 + 0x8 * 0x200))) + _0x39eb64) << (-0x267 + 0x6fb * -0x4 + -0x7 * -0x455)) ^ _0x39eb64))) + _0x128d32[0xd73 + -0xe3f + 0xd4] + (-0x882b6c12 + 0x26ddcab5 + 0x9d1 * 0x10fa2a)) << (-0x1 * -0xb31 + 0xa * -0x175 + 0x375)) | (_0x3952af >>> (0x106 * 0x26 + 0x2e9 + -0x29c1))) + _0x2a0c94) << (-0x198a + 0xb33 * -0x1 + 0x24bd)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ (_0x2a0c94 & ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x39eb64 & (_0x3952af ^ _0x2a0c94))) + _0x128d32[0x1d4f + -0x10ae + -0xc94] - (0x76d313f * 0xd + -0x5 * -0x7a635fc + -0x2 * 0x18573b92)) << (0x612 + -0x1 * 0x40 + -0x5cd)) | (_0x227f23 >>> (-0x12e9 * 0x2 + -0x1 * -0x19e7 + -0x1 * -0xc06))) + _0x3952af) << (0x10db + 0x10b5 * 0x1 + -0x3 * 0xb30)) ^ _0x3952af))) + _0x128d32[-0x796 + -0x13b9 + 0x1b51] - (-0x17e5b * 0x29 + 0x48058e0 + -0x132c045)) << (0x26d * -0x2 + 0x4 * -0x34e + -0x5 * -0x39f)) | (_0x39eb64 >>> (0x198d * -0x1 + -0x25d4 + -0xa94 * -0x6))) + _0x227f23) << (0x206d + -0xd3f + -0x132e)) ^ (_0x227f23 & ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x3952af & (_0x39eb64 ^ _0x227f23))) + _0x128d32[-0x1f * 0x95 + 0x6 * -0x3dc + -0x3 * -0xdbe] + (-0x2 * 0x5ec874bd + -0x4537c41d * -0x1 + 0xdfc82836)) << (0x1336 + -0x12bc + -0x6c)) | (_0x2a0c94 >>> (0x119 * -0x1d + -0x3 * 0xc41 + 0x44aa * 0x1))) + _0x39eb64) << (0xe * -0x29c + 0x4ea + 0x1f9e)) ^ _0x39eb64))) + _0x128d32[0x985 + -0x1177 + 0x1 * 0x7fe] - (-0x3d273af + -0x1 * -0x72611590 + 0x4471195)) << (0x112 * 0x15 + -0xa30 + -0x412 * 0x3)) | (_0x3952af >>> (0x1 * 0xe74 + 0x6 * 0x1f7 + -0x1a32))) + _0x2a0c94) << (0xf1 + -0xe43 * -0x2 + -0x1d77 * 0x1)), (_0x3952af = ((((_0x3952af += ((_0x113678 = (_0x39eb64 = ((((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[-0x87 * -0x1 + -0x1 * -0x1626 + -0x16a8] - (-0x3ca72 + -0xac995 + 0x145ac5)) << (-0x1231 + -0x1 * -0xb05 + 0x730)) | (_0x227f23 >>> (0x20dd * 0x1 + -0x16b8 + -0xa09))) + _0x3952af) << (0x1 * 0xe63 + 0xa34 * -0x2 + 0x605))) + _0x128d32[-0x9a * -0x23 + 0x25fd + -0x3b03] - (0xb06c444e + 0x2d68c * 0x1574 + 0x9 * -0xcf8fe07)) << (0x1f60 * -0x1 + -0x1fc2 + -0x1 * -0x3f2d)) | (_0x39eb64 >>> (0x1c0e + 0x7c * -0x3b + 0x9b * 0x1))) + _0x227f23) << (-0x1 * 0x7db + 0x143d * 0x1 + -0x2 * 0x631)) ^ _0x227f23) ^ (_0x2a0c94 = ((((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[0x1315 + 0x22f5 + -0x35ff] + (0x1 * -0xc1ee2861 + 0x5f64a13c + 0xd026e847)) << (0x10b * 0x15 + 0x9e2 + -0x1fb9)) | (_0x2a0c94 >>> (0x213e + -0x11 * -0x93 + -0x1 * 0x2af1))) + _0x39eb64) << (-0x4 * 0x7c8 + 0x1 * 0x33d + 0x1be3))) + _0x128d32[0x18c5 * 0x1 + 0x94d * -0x3 + 0x2 * 0x198] - (0xbbbcc3 + 0x1509 * -0x2a32 + 0x4d6a0f3)) << (0x12b5 * 0x1 + -0xc * 0xa2 + -0xb06)) | (_0x3952af >>> (-0x596 * 0x5 + 0x2 * -0x655 + 0x28a1))) + _0x2a0c94) << (0x5f * -0x36 + 0x2b1 * 0x4 + 0x946)), (_0x3952af = ((((_0x3952af += ((_0x113678 = (_0x39eb64 = ((((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[-0xaa9 + 0x6 * 0x54e + 0x7e * -0x2b] - (-0x1309d * -0x67b3 + -0x8e97ecd6 + 0x6e74d9cb)) << (-0x1 * 0x1169 + -0x1c3f + 0x2dac)) | (_0x227f23 >>> (-0x12f * 0x1d + 0x178 + 0x20f7))) + _0x3952af) << (-0x1554 + 0x2 * -0x136e + 0x9 * 0x6b0))) + _0x128d32[0x8bd * 0x4 + 0x993 + -0x2c83] + (-0x1ec1ce29 + 0x12d9d323 + 0x57c6caaf)) << (0x2f9 * 0x1 + 0x1a55 + -0x1d43)) | (_0x39eb64 >>> (-0xdf6 + 0x94 * 0x2 + 0xce3))) + _0x227f23) << (-0xd5 + -0x197e + 0x1a53)) ^ _0x227f23) ^ (_0x2a0c94 = ((((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[0x697 * -0x1 + -0x617 + 0xcb5] - (0x2 * -0x11de459 + 0xaabba88 + 0xd4c2ca)) << (-0x1198 * 0x1 + -0x42c * 0x3 + 0x2 * 0xf16)) | (_0x2a0c94 >>> (0x28e * 0x2 + 0x1547 + -0x125 * 0x17))) + _0x39eb64) << (0x45 * 0x21 + -0x14 * -0x7 + 0x971 * -0x1))) + _0x128d32[-0x1 * -0x118b + 0x1f4 + -0x1375] - (0x2 * -0x34ed62bd + -0x6d39a445 + -0x11854ad4f * -0x1)) << (-0x27f * -0x1 + -0x4 * 0x31a + 0xa00)) | (_0x3952af >>> (-0x319 + -0x1 * -0x247d + -0x215b * 0x1))) + _0x2a0c94) << (-0x1bc7 * 0x1 + 0x1 * -0x4f7 + 0x20be)), (_0x3952af = ((((_0x3952af += ((_0x113678 = (_0x39eb64 = ((((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[-0x1 * -0x1eb5 + -0x1ba5 + -0x3 * 0x101] + (0x338d6ddd + 0x1 * 0x3db4c799 + -0x48a6b6b0)) << (0x126a + 0x1 * 0x407 + -0x166d * 0x1)) | (_0x227f23 >>> (-0x1f97 + -0x2566 * -0x1 + 0x5b3 * -0x1))) + _0x3952af) << (0x2175 + 0x2187 * 0x1 + -0x42fc))) + _0x128d32[0x1701 + 0x1fb6 + 0x36b7 * -0x1] - (0x1e38ad99 + -0x3 * -0x1727b1c + -0xd3146e7)) << (0x15 * -0x18d + -0x4 * -0x75e + 0x324)) | (_0x39eb64 >>> (-0x7f8 + 0x1 * 0xc1 + 0x74c))) + _0x227f23) << (-0x86 * 0x27 + -0x1 * 0x1a93 + -0x17 * -0x20b)) ^ _0x227f23) ^ (_0x2a0c94 = ((((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[0x1 * -0x1c6f + -0x10f0 + -0x4a * -0x9d] - (-0x353a5 * 0xce7 + 0x510a05c * 0xe + 0xf144056)) << (0x2c * -0x8f + -0x20 * -0x11b + 0x2af * -0x4)) | (_0x2a0c94 >>> (-0x167c * -0x1 + 0x1bef * -0x1 + 0x583))) + _0x39eb64) << (-0x3 * 0x3b + 0x1555 + 0xa52 * -0x2))) + _0x128d32[0x35 * -0x27 + -0x1 * 0xdb8 + -0x1 * -0x15d1] + (0x2e39f97 * 0x1 + -0x1 * 0x58f09b4 + 0x7338722)) << (0x1d3 * -0x6 + 0x1 * 0x171b + 0x406 * -0x3)) | (_0x3952af >>> (0x3c1 + -0x1cbf + 0x1907))) + _0x2a0c94) << (0x1b73 + 0x1d44 + 0x38b7 * -0x1)), (_0x3952af = ((((_0x3952af += ((_0x113678 = (_0x39eb64 = ((((_0x39eb64 += ((_0x2fd641 = _0x3952af ^ _0x2a0c94) ^ (_0x227f23 = ((((_0x227f23 += (_0x2fd641 ^ _0x39eb64) + _0x128d32[0x30b * 0x2 + 0xa52 + -0x105f] - (0x131 * 0x25e655 + -0xe61e * 0x48b + 0xe5c * -0x33bb)) << (0x17a1 + -0x26 * 0x3f + 0x3 * -0x4c1)) | (_0x227f23 >>> (0x1079 + -0x13 * 0xf5 + 0x1d2))) + _0x3952af) << (-0xf27 + -0x1 * -0x21d1 + 0x955 * -0x2))) + _0x128d32[0x20e * -0x3 + -0x4a7 * 0x8 + 0x2b6e] - (0x1 * 0x79f0ea3 + -0x184cea1d + -0x11d * -0x2590d9)) << (0x12e3 + 0x12b * -0x2 + -0x1082)) | (_0x39eb64 >>> (-0x485 * 0x2 + -0x61 * 0x1a + 0x12f9))) + _0x227f23) << (0x1 * -0x34c + -0x6 * 0x4dc + -0x1 * -0x2074)) ^ _0x227f23) ^ (_0x2a0c94 = ((((_0x2a0c94 += (_0x113678 ^ _0x3952af) + _0x128d32[-0x3e3 + 0x22d * -0x2 + 0x84c] + (-0xdb8446c + -0x1 * -0x5cb3a83 + 0x278f86e1)) << (-0x7 * -0x3f1 + 0x17f * 0x7 + -0x2600)) | (_0x2a0c94 >>> (-0x47e + 0xce * 0x2 + 0x2 * 0x179))) + _0x39eb64) << (0x1 * 0x9fe + 0x1 * 0x17f5 + -0x21f3))) + _0x128d32[-0x18 * -0x18e + -0x1dff + -0x74f * 0x1] - (0x12fee507 + -0x1 * 0x6a5c4769 + -0x1 * -0x92b10bfd)) << (0x5 * -0x52a + -0x1e75 + 0xde * 0x41)) | (_0x3952af >>> (0x116b + -0x1 * 0x9ed + 0x53 * -0x17))) + _0x2a0c94) << (0x264e * -0x1 + -0x11fd + 0x384b)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[-0x1524 + 0x65 * 0x5b + 0x1 * -0xec3] - (0x63c0c3 * 0x1f + 0x11a61fd * -0xc + -0xcff1dfb * -0x1)) << (0x36c + -0x4eb * 0x5 + 0x1531)) | (_0x227f23 >>> (-0x941 * -0x2 + -0x1b * -0x9b + -0x22c1))) + _0x3952af) << (0x1862 + -0x1359 + -0x509)) | ~_0x2a0c94)) + _0x128d32[-0x26d + -0x6 * 0xbd + 0x6e2] + (-0x690c7 * 0xd6d + 0x2c437c8e * 0x1 + -0x3786a162 * -0x2)) << (0x54a + -0x1bd3 + 0x1693)) | (_0x39eb64 >>> (0x1076 + 0xa0d + -0x1a6d))) + _0x227f23) << (-0x1d37 + 0x1 * 0x14fb + 0x83c)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[0x190f * -0x1 + -0x1503 + 0x2e20] - (0x12aa3 * 0x80ad + 0x5 * 0x123e2fa3 + -0x9ce661fd)) << (-0x204a + -0x22cf + 0x4328)) | (_0x2a0c94 >>> (0x1 * 0xcac + -0x1bbf * -0x1 + -0x142d * 0x2))) + _0x39eb64) << (-0x11b4 + 0x10b1 * 0x1 + -0x25 * -0x7)) | ~_0x227f23)) + _0x128d32[0x1 * -0x10d + 0x5f4 + -0x19 * 0x32] - (0x2181582 + -0x55ca10e + 0x6b0eb53)) << (-0xd3d * 0x1 + -0x1dd7 + -0x1 * -0x2b29)) | (_0x3952af >>> (0x676 + 0xa84 * 0x1 + -0x10ef))) + _0x2a0c94) << (-0x2 * 0xc83 + 0x15 * -0x10c + -0x1781 * -0x2)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[0x2 * -0x527 + 0x246c + -0x8e * 0x2f] + (0x62359ef1 + 0xc3bd213a + -0xc0976668)) << (-0x22fa * 0x1 + 0x2af + 0x2051)) | (_0x227f23 >>> (-0x92b + -0x4b4 * 0x1 + 0xdf9))) + _0x3952af) << (0x494 + -0x1902 + -0x1 * -0x146e)) | ~_0x2a0c94)) + _0x128d32[0x1d8 * 0x1 + 0x1 * -0x5ce + 0x3f9] - (-0x324 * -0x49722 + 0xde * 0x31ad3b + -0x1bba29be * -0x2)) << (0x941 + -0x1651 + -0x4e * -0x2b)) | (_0x39eb64 >>> (0x2 * -0xc2 + -0x112a + 0x12c4))) + _0x227f23) << (0x1369 + -0x1261 + -0x3 * 0x58)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[0x10c5 + 0x78f + 0x1 * -0x184a] - (-0x3b62a * 0x6 + 0x15245b + 0x89612 * 0x2)) << (0x252f + -0x5 * -0x661 + -0x4505)) | (_0x2a0c94 >>> (0x251e + 0x6 * 0x2b7 + -0x3557 * 0x1))) + _0x39eb64) << (-0x1 * -0xa79 + -0x8d * -0x33 + -0x2690)) | ~_0x227f23)) + _0x128d32[0x395 * 0x8 + -0x24a9 + -0x52 * -0x19] - (-0xc3191853 + -0x57fdcd8 * 0x29 + -0x141d00ee * -0x1b)) << (0x132b * -0x1 + -0x13 * -0x15 + 0x11b1)) | (_0x3952af >>> (-0x175f + 0x16 * 0xc2 + -0x2 * -0x35f))) + _0x2a0c94) << (-0xc * -0x2de + -0x1 * -0x261a + 0x1 * -0x4882)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[0x4 * -0x527 + -0xb71 + 0x2015 * 0x1] + (0x2 * -0x2405587c + 0x963dc885 * 0x1 + 0x217566c2)) << (0x14cb + -0x647 * -0x1 + -0x1b0c)) | (_0x227f23 >>> (-0xbd * 0x30 + -0x13 * 0x14f + 0x7 * 0x8a1))) + _0x3952af) << (-0xd * 0x215 + 0xcc + 0x1a45)) | ~_0x2a0c94)) + _0x128d32[-0x638 * 0x6 + -0x25fa + 0x4b59] - (0xab1cd2 + -0x184b1f6 + 0x2acae44)) << (-0x177b + -0x500 + 0x1c85)) | (_0x39eb64 >>> (-0x1e73 + -0x3 * 0x1f1 + -0x2 * -0x122e))) + _0x227f23) << (0xb5 * -0x3 + 0x158f + -0x4 * 0x4dc)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[-0xe39 + 0x452 + 0x9ed] - (0x5a22d2a4 + 0x3a146128 + 0x154a34 * -0x298)) << (0x1 * -0x1fd0 + 0x1837 * 0x1 + 0x7a8)) | (_0x2a0c94 >>> (0x1212 + 0x2 * -0xc47 + 0x68d))) + _0x39eb64) << (-0x20ba + 0xbb2 + -0x8 * -0x2a1)) | ~_0x227f23)) + _0x128d32[0x283 * 0x8 + -0x5f * 0x37 + 0x5e] + (-0x15db9faa + 0x3841d * -0x1db3 + 0xcc505a92)) << (-0x172f + -0x5f * -0x1 + 0x16e5)) | (_0x3952af >>> (0x6c + 0x2 * 0x530 + 0xac1 * -0x1))) + _0x2a0c94) << (0x3 * 0x312 + 0x19 * -0x107 + 0x1079)), (_0x3952af = ((((_0x3952af += ((_0x39eb64 = ((((_0x39eb64 += (_0x3952af ^ ((_0x227f23 = ((((_0x227f23 += (_0x2a0c94 ^ (_0x3952af | ~_0x39eb64)) + _0x128d32[-0x5bc + -0x1 * -0x887 + -0x1 * 0x2c7] - (0xd0d1959 + 0x9a4d1b1 + -0xe05698c)) << (0x3 * 0x6a7 + 0x252e + -0x391d)) | (_0x227f23 >>> (-0x2292 + -0x1385 + 0x1 * 0x3631))) + _0x3952af) << (-0x2483 * -0x1 + 0x93e + 0xd * -0x385)) | ~_0x2a0c94)) + _0x128d32[-0x1fd2 + 0x1bb0 + -0x1 * -0x42d] - (-0x9b7 * 0xd9fae + -0x9fdcf8b * -0x7 + 0xb3bb54 * 0xb8)) << (0x1f * 0xec + -0x260 + -0x18a * 0x11)) | (_0x39eb64 >>> (0x140 * -0x6 + 0x2231 * -0x1 + 0x29c7))) + _0x227f23) << (0x26ef * -0x1 + -0x112b + 0x2b * 0x14e)) ^ ((_0x2a0c94 = ((((_0x2a0c94 += (_0x227f23 ^ (_0x39eb64 | ~_0x3952af)) + _0x128d32[-0x1 * -0x100d + 0xdc0 + -0x1d * 0x107] + (0x43dc7475 + 0x524cbd91 + -0x82661 * 0xd2b)) << (-0x1f * -0xf + -0x1d3a + -0x1 * -0x1b78)) | (_0x2a0c94 >>> (0x235b + 0x162b + -0x3975))) + _0x39eb64) << (-0xf * -0x27b + -0xc58 + -0x18dd)) | ~_0x227f23)) + _0x128d32[-0x72 * -0x1f + 0xac4 + -0x1889] - (0xa * -0x3c812a2 + -0x2c * 0x1bc4a2 + -0x3 * -0x15053b89)) << (0x4 * 0x9c2 + -0xd46 * 0x2 + -0xc67)) | (_0x3952af >>> (-0x8b9 + -0x1ed3 * 0x1 + -0x1 * -0x2797))) + _0x2a0c94) << (-0x1 * -0xede + 0x15d3 + -0x1f * 0x12f)), this['first'] ? ((this['h0'] = (_0x227f23 + (-0x295123b + 0xc62a6020 * 0x1 + -0x22 * 0x2b71052)) << (-0x2 * -0x602 + -0x1 * 0x12c2 + 0x6be)), (this['h1'] = (_0x3952af - (0x3a5b52c + 0x1d978e61 + 0x7 * -0x26f46ba)) << (0x5ea * 0x4 + 0xe5 + -0x4e9 * 0x5)), (this['h2'] = (_0x2a0c94 - (0xa6be44c7 + 0xc54d85a4 + -0x104c6a769)) << (0x6d * 0x53 + 0x1809 + -0x3b60)), (this['h3'] = (_0x39eb64 + (-0x1fdbc0b + 0x1 * 0x1a1047ff + 0x85f6 * -0xf0d)) << (0x26e8 + -0x5d * 0x1f + 0x151 * -0x15)), (this[_0x2f0149(0x19f)] = !(0x25a2 + -0x5 * 0x1d5 + -0x38f * 0x8))) : ((this['h0'] = (this['h0'] + _0x227f23) << (0x923 + 0xb1c + -0x143f)), (this['h1'] = (this['h1'] + _0x3952af) << (-0x23 * 0xc0 + 0x1aef + -0xaf)), (this['h2'] = (this['h2'] + _0x2a0c94) << (-0x1b53 + -0x1acc + -0xa3 * -0x55)), (this['h3'] = (this['h3'] + _0x39eb64) << (-0xba0 * 0x1 + 0x146 + 0xa * 0x109))) }), (_0x22f902[_0x2db296(0x344)]['hex'] = function () { this['finalize']() var _0x58d18c = this['h0'], _0x4e2807 = this['h1'], _0x41534b = this['h2'], _0x136921 = this['h3'] return ( _0x142491[(_0x58d18c >> (0x3cb * -0x4 + -0x6e * -0x3 + 0xde6)) & (0x3b * 0x47 + 0x1567 + -0x25b5)] + _0x142491[(-0x1731 + -0x16e + 0x9 * 0x2be) & _0x58d18c] + _0x142491[(_0x58d18c >> (-0xa78 + 0x18d4 + 0xe5 * -0x10)) & (0x81e + -0x6 * 0x529 + 0x16e7)] + _0x142491[(_0x58d18c >> (0x1894 + -0x3c + -0x1850)) & (-0x2228 * -0x1 + 0x3 * 0x4ff + -0x3116)] + _0x142491[(_0x58d18c >> (-0x67 * -0x1 + -0x1842 + 0x17ef)) & (0x580 * -0x6 + 0x1b * 0x171 + -0x5dc)] + _0x142491[(_0x58d18c >> (-0x1 * -0x709 + 0x1594 + -0x1 * 0x1c8d)) & (0x1633 + -0x70d + -0xf17)] + _0x142491[(_0x58d18c >> (-0xaf6 + 0x1ddb * 0x1 + -0x12c9)) & (-0x4b * 0x7b + 0x5 * 0x41b + 0xf91)] + _0x142491[(_0x58d18c >> (-0x1 * 0x1543 + -0x1795 * -0x1 + -0x23a)) & (-0x1e70 + 0xcc5 + -0x11ba * -0x1)] + _0x142491[(_0x4e2807 >> (0x651 + -0x10f7 * -0x2 + -0x283b)) & (0x1199 + -0x47 * -0x59 + -0x2a39)] + _0x142491[(0xe3 * -0x22 + 0x2479 + 0x644 * -0x1) & _0x4e2807] + _0x142491[(_0x4e2807 >> (0x121a + 0x1a84 + -0x2c92)) & (-0x65 * -0x4a + -0x5db + -0x1748)] + _0x142491[(_0x4e2807 >> (0x14a3 + -0x11 * 0x55 + -0x5 * 0x2fe)) & (-0x24e3 * -0x1 + 0xf64 + -0x3438)] + _0x142491[(_0x4e2807 >> (0x1cf + -0x1c89 + -0x2 * -0xd67)) & (-0xd47 * -0x2 + -0x1 * 0x221b + 0x1e7 * 0x4)] + _0x142491[(_0x4e2807 >> (0x673 + 0x1d12 + -0x1 * 0x2375)) & (0x12ce + -0x8 * -0xb5 + -0x1867)] + _0x142491[(_0x4e2807 >> (0x1 * 0x1499 + 0x1a6b * 0x1 + -0x98 * 0x4f)) & (0x1516 + -0x147 * -0x2 + -0x1795 * 0x1)] + _0x142491[(_0x4e2807 >> (0x4 * 0x570 + -0x2 * 0x622 + -0x2 * 0x4b2)) & (-0x6 * -0x15d + -0x7eb + -0x34)] + _0x142491[(_0x41534b >> (0x1738 + -0x6 * 0x23b + -0x3 * 0x346)) & (-0x97 * -0x3a + 0x3a6 + -0x25cd)] + _0x142491[(-0x48 * -0x11 + 0x1 * -0x2502 + 0x13 * 0x1b3) & _0x41534b] + _0x142491[(_0x41534b >> (-0x1 * -0x1556 + 0x3 * 0x623 + -0x27b3 * 0x1)) & (-0x6b * 0x1f + 0x1 * -0x49 + -0x3 * -0x46f)] + _0x142491[(_0x41534b >> (-0x794 + -0x1 * 0x2443 + 0x2bdf)) & (0x26ca + -0xb02 + 0x2f * -0x97)] + _0x142491[(_0x41534b >> (0x177f + -0x57b + -0x11f * 0x10)) & (0x1eed + 0xbb2 + -0x2a90)] + _0x142491[(_0x41534b >> (0xab7 * -0x2 + 0x3ba + 0x11c4)) & (-0x1621 + 0xa3f * 0x2 + -0xd9 * -0x2)] + _0x142491[(_0x41534b >> (0x607 + -0x2065 + 0x1a7a)) & (0x2 * -0xb0f + 0x629 * -0x5 + 0x1a7d * 0x2)] + _0x142491[(_0x41534b >> (-0x2205 + 0x20ac + 0x171)) & (-0x1 * -0x1337 + 0x6e * -0x1 + -0x22 * 0x8d)] + _0x142491[(_0x136921 >> (-0x845 + -0x1 * 0x267b + 0x1762 * 0x2)) & (0x340 + -0x21 * 0xcb + 0x16fa)] + _0x142491[(0x4 * -0x8e2 + -0xdea + 0x3181) & _0x136921] + _0x142491[(_0x136921 >> (0x1784 + 0xa * 0x31b + -0x1 * 0x3686)) & (-0x26 * 0x4f + -0x1 * -0xca8 + 0xdf * -0x1)] + _0x142491[(_0x136921 >> (0x1823 * -0x1 + 0xe5c * -0x2 + 0x1 * 0x34e3)) & (0x34e * 0x6 + 0x47f + -0x1844 * 0x1)] + _0x142491[(_0x136921 >> (0x1 * -0x10af + 0x39a + 0xd29)) & (-0xea2 + 0x2 * -0xad2 + 0x2455)] + _0x142491[(_0x136921 >> (0xadf + 0x2db * -0x7 + 0x92e)) & (-0x493 * 0x3 + 0x15e1 + -0x819)] + _0x142491[(_0x136921 >> (-0x22d6 + 0x20 * -0x17 + 0x25d2)) & (-0x17 * 0x83 + 0x1214 + -0x640)] + _0x142491[(_0x136921 >> (-0x96e + -0x1e99 + 0x281f)) & (-0x18c8 + 0x33 * 0x89 + -0x274)] ) }), (_0x22f902['prototype'][_0x2db296(0x3ae)] = _0x22f902[_0x2db296(0x344)]['hex']), (_0x22f902[_0x2db296(0x344)]['digest'] = function () { var _0x5a0a9e = _0x2db296 this[_0x5a0a9e(0x1d9)]() var _0x2a8796 = this['h0'], _0x2d7c31 = this['h1'], _0x1378d3 = this['h2'], _0x2e667f = this['h3'] return [ (0x1 * 0x4bd + 0x1f15 + 0x5 * -0x6f7) & _0x2a8796, (_0x2a8796 >> (0xbcd + -0x25f7 + 0x1a32)) & (0x1507 + -0x177d + 0x1 * 0x375), (_0x2a8796 >> (-0x141c + 0x1ae2 + -0x6b6)) & (0x132a + -0x3 * 0x423 + 0xb * -0x86), (_0x2a8796 >> (-0x1 * -0x261f + 0x115 * -0xc + -0x190b)) & (0x1233 * -0x1 + 0xacf * -0x3 + 0x339f), (-0x16a0 + 0x1002 + 0x79d * 0x1) & _0x2d7c31, (_0x2d7c31 >> (-0x2 * 0xff4 + -0x541 * 0x2 + -0xe26 * -0x3)) & (0x54e + -0x1c * -0x148 + -0x282f * 0x1), (_0x2d7c31 >> (-0x4 * -0x83f + 0x20ab * -0x1 + -0x41)) & (0x427 * 0x5 + 0xdd1 + -0x2195 * 0x1), (_0x2d7c31 >> (0xf * -0x201 + 0x1c26 + -0x9 * -0x39)) & (0x7 * -0x235 + 0x1be + 0xeb4 * 0x1), (0x34 * 0x9b + 0xa36 + -0x28b3) & _0x1378d3, (_0x1378d3 >> (0x463 * 0x1 + -0x1f0d + 0x1ab2)) & (0x13 * -0x17f + -0x536 + 0x22a2), (_0x1378d3 >> (0x4a7 + -0x1a4 + -0x2f3)) & (0x1066 + 0xb3d + -0x1aa4), (_0x1378d3 >> (-0xc00 + -0x2 * 0xfcb + 0x2bae)) & (0x11a7 * -0x1 + 0x3a1 * -0x1 + 0x1647), (-0xa38 + -0x1304 + 0x1e3b) & _0x2e667f, (_0x2e667f >> (0x1102 + 0x1896 + -0x2f8 * 0xe)) & (-0x15b2 * -0x1 + -0xa6 * 0x31 + -0xf * -0xbd), (_0x2e667f >> (0x25a2 + -0x4 * 0x103 + -0x2186)) & (-0xa83 * -0x3 + -0x15f1 + -0x899), (_0x2e667f >> (0xb95 * 0x3 + -0x1a34 + -0x873)) & (0xfb6 * -0x2 + 0x3b * 0x3a + 0x130d) ] }), (_0x22f902[_0x2db296(0x344)][_0x2db296(0x238)] = _0x22f902['prototype'][_0x2db296(0x19b)]), (_0x22f902['prototype'][_0x2db296(0x249)] = function () { var _0x45ab2e = _0x2db296 this[_0x45ab2e(0x1d9)]() var _0x31d586 = new ArrayBuffer(0x13 * -0x20e + -0x4 * -0x62f + 0xe5e), _0x2d9fbd = new Uint32Array(_0x31d586) return ( (_0x2d9fbd[-0xbcc + -0xf5 * -0x3 + -0x5 * -0x1c9] = this['h0']), (_0x2d9fbd[0x5 * 0x103 + 0x26ee + -0x2bfc] = this['h1']), (_0x2d9fbd[0x7d + -0x1b05 * -0x1 + -0x1b80] = this['h2']), (_0x2d9fbd[0x1 * 0x1c1c + 0x1 * 0x4eb + -0x2104] = this['h3']), _0x31d586 ) }), (_0x22f902['prototype']['buffer'] = _0x22f902[_0x2db296(0x344)][_0x2db296(0x249)]), (_0x22f902[_0x2db296(0x344)][_0x2db296(0x25f)] = function () { var _0x16e12f = _0x2db296 for ( var _0x1dad5c, _0x24f20d, _0x70d99b, _0xb48dfc = '', _0x13e0cb = this[_0x16e12f(0x238)](), _0x12e65e = -0x719 * -0x5 + -0x747 * -0x5 + 0x170 * -0x32; _0x12e65e < -0x8c + 0x164f + -0x15b4; ) (_0x1dad5c = _0x13e0cb[_0x12e65e++]), (_0x24f20d = _0x13e0cb[_0x12e65e++]), (_0x70d99b = _0x13e0cb[_0x12e65e++]), (_0xb48dfc += _0xcb4d61[_0x1dad5c >>> (0x13b + 0x209 * -0xb + 0x152a)] + _0xcb4d61[ (0x13d3 + 0x4c7 + -0x185b) & ((_0x1dad5c << (0x1334 + 0x1dd7 + 0x7 * -0x701)) | (_0x24f20d >>> (-0x3b3 * 0xa + -0x17b * -0x13 + -0x1 * -0x8e1))) ] + _0xcb4d61[ (-0x25dd + 0x14bd + 0x115f) & ((_0x24f20d << (-0x787 + 0x888 + -0xff)) | (_0x70d99b >>> (0xe74 + -0x104f + 0xd * 0x25))) ] + _0xcb4d61[(0x68e + -0x1082 + -0x175 * -0x7) & _0x70d99b]) return ( (_0x1dad5c = _0x13e0cb[_0x12e65e]), (_0xb48dfc += _0xcb4d61[_0x1dad5c >>> (0x2b * -0x77 + 0x29e * 0x2 + 0xec3)] + _0xcb4d61[(_0x1dad5c << (-0x14c0 + -0x2 * -0x11a4 + 0x2 * -0x742)) & (0xe5f + -0x1dab + 0xf8b * 0x1)] + '==') ) }) var _0x336469 = _0x1edabb() _0x299a21 ? (_0xb9c7d1[_0x2db296(0x1b8)] = _0x336469) : ((_0x11d177[_0x2db296(0x35c)] = _0x336469), _0x5efc8f && (void (0x1118 + -0x25 * 0x98 + 0x1a0 * 0x3))(function () { return _0x336469 })) })() }) function _0x5dd467(_0x2e8eb5) { var _0x344c50 = _0x5612de return w_0x5c3140( _0x344c50(0x333), { get 0x0() { return _0x90795 }, 0x1: arguments, 0x2: _0x2e8eb5 }, this ) } function _0x176a57() { var _0x33742c = _0x5612de return !!document[_0x33742c(0x373)] } function _0x1230e7() { return 'undefined' != typeof InstallTrigger } function _0xf8ccf1() { var _0x25d57d = _0x5612de return ( /constructor/i[_0x25d57d(0x22b)](window['HTMLElement']) || _0x25d57d(0x226) === (!window['safari'] || (_0x25d57d(0x384) != typeof safari && safari['pushNotification']))[_0x25d57d(0x3ae)]() ) } function _0x30c916() { var _0x56f7c2 = _0x5612de return new Date()[_0x56f7c2(0x16d)]() } function _0x5af46a(_0xeaff35) { return null == _0xeaff35 ? '' : 'boolean' == typeof _0xeaff35 ? (_0xeaff35 ? '1' : '0') : _0xeaff35 } function _0x325f58(_0x3fdcb7, _0x2838bc) { var _0x17d12c = _0x5612de _0x2838bc || (_0x2838bc = _0x17d12c(0x24c)) for (var _0x3b8f2c = '', _0x98f0de = _0x3fdcb7; _0x98f0de > -0x2 * -0x90e + 0x4 * -0x3ae + -0x364; --_0x98f0de) _0x3b8f2c += _0x2838bc[Math[_0x17d12c(0x1cf)](Math['random']() * _0x2838bc[_0x17d12c(0x259)])] return _0x3b8f2c } var _0x39693d = { sec: 0x9, asgw: 0x5, init: 0x0 }, _0x6caf = { bogusIndex: 0x0, msNewTokenList: [], moveList: [], clickList: [], keyboardList: [], activeState: [], aidList: [] } function _0x53b77d(_0x357347) { return w_0x5c3140( '484e4f4a403f5243001714366d6da13c00000025f8c25369000000ee00110307070002161103021200031103070700021303062b2f11030207000335490700044211010044001400011101014a1200001100010700010d05000000003c000e00054303491101034a12000607000711000143024911010433000611010412000833000911010412000812000947002100110107070002161101021200031101070700021303062b2f110102070003354902110105430047004f11010433002511010412000a11010412000b190400962934001111010412000c11010412000d190400962947002100110107070002161101021200031101070700021303062b2f11010207000335490842000e0e7170737c7b7045677a657067616c027c7108717077607272706707707b63767a71700003727061047c7b737a02307607767a7b667a797007737c67707760720a7a60617067427c71617d0a7c7b7b7067427c71617d0b7a606170675d707c727d610b7c7b7b70675d707c727d61', { get 0x0() { return Image }, 0x1: Object, get 0x2() { return _0x6caf }, get 0x3() { return console }, get 0x4() { return window }, get 0x5() { return _0x1230e7 }, 0x6: arguments, 0x7: _0x357347 }, this ) } function _0x3ed707() { var _0x2077c7 = _0x5612de return w_0x5c3140( _0x2077c7(0x31d), { get 0x0() { return navigator }, get 0x1() { var _0x573a52 = _0x2077c7 return _0x573a52(0x384) != typeof global ? global : void (-0x11 * -0x1cf + 0x95 * 0x16 + -0x1 * 0x2b8d) }, 0x2: Object, get 0x3() { var _0x4b9092 = _0x2077c7 return _0x4b9092(0x384) != typeof process ? process : void (-0x65 * 0x2 + 0x2579 * 0x1 + -0x1 * 0x24af) }, get 0x4() { return _0x1db123 }, 0x5: arguments }, this ) } function _0x328bde(_0xacb410, _0x4ed7bd, _0x49d137) { var _0x197e65 = _0x5612de, _0x2d8b28 = _0x197e65(0x2ce), _0x4dd4b8 = '=' _0x49d137 && (_0x4dd4b8 = ''), _0x4ed7bd && (_0x2d8b28 = _0x4ed7bd) for ( var _0x1aa067, _0x3b8c55 = '', _0x2d1a36 = 0xe0f * 0x2 + -0x35b * -0x8 + 0x29e * -0x15; _0xacb410[_0x197e65(0x259)] >= _0x2d1a36 + (0x73 * -0x26 + -0xb4e + 0x1c63); ) (_0x1aa067 = (((-0x1cb9 + 0x2c6 + -0x1 * -0x1af2) & _0xacb410[_0x197e65(0x195)](_0x2d1a36++)) << (0x1de9 + 0x1c + -0x1 * 0x1df5)) | (((-0x1 * 0xd91 + -0x23a + 0x10ca) & _0xacb410[_0x197e65(0x195)](_0x2d1a36++)) << (-0x16 * 0x135 + 0x9e2 * 0x3 + -0x188 * 0x2)) | ((-0x752 + -0x2 * 0xaf3 + 0x1e37) & _0xacb410[_0x197e65(0x195)](_0x2d1a36++))), (_0x3b8c55 += _0x2d8b28[_0x197e65(0x25c)]( ((0x1c78125 + -0x1df1122 + -0xb * -0x190d17) & _0x1aa067) >> (0x59 * 0x4f + -0x1176 + -0x1 * 0x9ef) )), (_0x3b8c55 += _0x2d8b28['charAt']( ((-0x1 * 0x13b6b + -0x13 * -0x65aa + -0x26033) & _0x1aa067) >> (0x17ea * -0x1 + 0xef7 + 0x8ff) )), (_0x3b8c55 += _0x2d8b28['charAt']( ((-0x1 * 0x16bd + 0x115 + 0x10a * 0x24) & _0x1aa067) >> (0x29c * -0x1 + -0x1 * 0x1475 + 0x1717) )), (_0x3b8c55 += _0x2d8b28[_0x197e65(0x25c)]((-0xc * 0x196 + 0x1fae + -0xc67) & _0x1aa067)) return ( _0xacb410[_0x197e65(0x259)] - _0x2d1a36 > -0x69f + -0x1 * 0xe5c + 0x14fb && ((_0x1aa067 = (((0x740 + -0x1ed1 + 0x1890) & _0xacb410['charCodeAt'](_0x2d1a36++)) << (-0x7 * 0xec + 0x2167 * 0x1 + -0x1ae3)) | (_0xacb410['length'] > _0x2d1a36 ? ((0x16aa + -0x762 * 0x1 + -0xe49) & _0xacb410[_0x197e65(0x195)](_0x2d1a36)) << (0x1af7 + -0x26be + 0xbcf) : 0x1 * -0x649 + -0x1 * 0xe16 + 0x2e9 * 0x7)), (_0x3b8c55 += _0x2d8b28[_0x197e65(0x25c)]( ((-0x1 * 0x484e9 + -0x13c88 * -0x4a + -0x28bd * -0x40d) & _0x1aa067) >> (0x6c * -0x4a + -0x81c * -0x2 + 0xf12) )), (_0x3b8c55 += _0x2d8b28['charAt'](((-0x1ad98 + 0x1a5c8 + 0x3f7d0) & _0x1aa067) >> (0x1f95 + -0x1c06 + -0x383))), (_0x3b8c55 += _0xacb410['length'] > _0x2d1a36 ? _0x2d8b28[_0x197e65(0x25c)](((-0x2447 + -0x1 * -0x1efe + 0x1509) & _0x1aa067) >> (0x1d66 + 0x2 * 0x202 + -0x2164)) : _0x4dd4b8), (_0x3b8c55 += _0x4dd4b8)), _0x3b8c55 ) } function _0x389396(_0x49fdfd, _0x32eedf) { var _0x36dcb8 = _0x5612de return w_0x5c3140( _0x36dcb8(0x3ad), { 0x0: arguments, 0x1: _0x49fdfd, 0x2: _0x32eedf }, this ) } function _0x3262d3(_0xb01975) { var _0x55341a = _0x5612de return _0x55341a(0x315)[_0x55341a(0x2c5)](_0xb01975) } function _0xb5350b(_0x1289f5) { var _0x341e09 = _0x5612de, _0x5b1849, _0x40ad1e, _0x341488, _0x5980c5, _0x31f759, _0x5bebd7 = '' for ( _0x5b1849 = 0x13d5 + -0xc4f * 0x1 + -0x786; _0x5b1849 < _0x1289f5[_0x341e09(0x259)] - (0xe50 * 0x1 + 0x17f3 + -0x2640); _0x5b1849 += -0xeed + 0x1 * 0x10c0 + -0x1cf * 0x1 ) (_0x40ad1e = _0x3262d3(_0x1289f5[_0x341e09(0x25c)](_0x5b1849))), (_0x341488 = _0x3262d3(_0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (0x1103 + 0xa86 + 0x1 * -0x1b88)))), (_0x5980c5 = _0x3262d3(_0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (-0x1c54 + -0xf15 + 0x2b6b)))), (_0x31f759 = _0x3262d3(_0x1289f5['charAt'](_0x5b1849 + (0xd1a + 0x1 * -0x175d + -0x5 * -0x20e)))), (_0x5bebd7 += String[_0x341e09(0x1e2)]( (_0x40ad1e << (0x33 * -0x3f + 0xe73 * -0x2 + 0x2975)) | (_0x341488 >>> (0x12d2 + 0x851 + -0x1b1f)) )), '=' !== _0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (0x51 * -0x25 + -0x21d * 0x12 + 0x31c1 * 0x1)) && (_0x5bebd7 += String['fromCharCode']( ((_0x341488 << (-0xa0c + 0xee3 + -0x4d3)) & (0x1 * 0x397 + -0x113f + 0xe98)) | ((_0x5980c5 >>> (0x2161 + 0x1b7 * -0x5 + 0xc66 * -0x2)) & (0x22bb + -0xf08 + 0x6 * -0x346)) )), '=' !== _0x1289f5[_0x341e09(0x25c)](_0x5b1849 + (0x125d * 0x2 + -0x3d * -0x31 + 0x146 * -0x26)) && (_0x5bebd7 += String[_0x341e09(0x1e2)]( ((_0x5980c5 << (-0x2650 + 0x17 * 0xe9 + -0x3 * -0x5cd)) & (0x754 + -0x5df + -0xb5)) | _0x31f759 )) return _0x5bebd7 } ; (_0x6caf[_0x5612de(0x380)] = -0x14e * -0x2 + 0x2519 + -0x217 * 0x13), (_0x6caf['msToken'] = ''), (_0x6caf[_0x5612de(0x263)] = _0x39693d[_0x5612de(0x3b9)]), (_0x6caf[_0x5612de(0x3b5)] = ''), (_0x6caf['ttwid'] = ''), (_0x6caf[_0x5612de(0x316)] = ''), (_0x6caf[_0x5612de(0x339)] = '') var _0x28d239 = 0x778 + 0xa41 + 0x1 * -0x11b9, _0x2d6b72, _0x1e9bba, _0xdc7355, _0xf08186 function _0x33f406(_0x4b5fb5) { var _0x1d1da4 = _0x5612de return ( (_0x4b5fb5 &= -0x2632 + 0x3 * -0x591 + 0x3724), String[_0x1d1da4(0x1e2)]( _0x4b5fb5 + (_0x4b5fb5 < 0x22f * 0x1 + -0x1cac + 0x3 * 0x8dd ? -0xd * 0x123 + 0x19ac + -0x552 * 0x2 : _0x4b5fb5 < -0x1 * -0x1646 + 0x1 * -0x1f21 + -0x305 * -0x3 ? -0x2b4 * 0x1 + -0x45 * 0xb + -0x2 * -0x2f9 : _0x4b5fb5 < 0x1 * 0x70c + 0x123f + -0x190d * 0x1 ? -(0x1f73 + -0x1 * -0x3d7 + -0x46 * 0x81) : -(-0x248f + 0x20d3 + 0x3cd)) ) ) } function _0x4da136(_0x620f42) { var _0xca40fa = _0x33f406 return ( _0xca40fa(_0x620f42 >> (0x420 * -0x4 + -0x53f * -0x4 + -0x464)) + _0xca40fa(_0x620f42 >> (-0x1492 + -0x11c3 + -0x3 * -0xccd)) + _0xca40fa(_0x620f42 >> (0x1479 + 0x571 * 0x6 + -0x795 * 0x7)) + _0xca40fa(_0x620f42 >> (-0x1d * 0x4f + 0x313 * -0xb + 0x2aca)) + _0xca40fa(_0x620f42) ) } ; (_0x2d6b72 = _0x1e9bba = function (_0x5d2d39) { return (_0x2d6b72 = _0xdc7355), (_0x28d239 = _0x5d2d39), _0x4da136(_0x5d2d39 >> (-0x418 * 0x8 + 0x9fe + 0x7c * 0x2f)) }), (_0xdc7355 = function (_0x135d9a) { _0x2d6b72 = _0xf08186 var _0x9cdabb = (_0x28d239 << (-0xa41 + -0x164f + 0x2b9 * 0xc)) | (_0x135d9a >>> (0xee4 + 0x1 * -0x143 + 0xcd * -0x11)) return (_0x28d239 = _0x135d9a), _0x4da136(_0x9cdabb) }), (_0xf08186 = function (_0x36c054) { return ( (_0x2d6b72 = _0x1e9bba), _0x4da136((_0x28d239 << (-0x302 + 0x1 * 0x2447 + -0x7 * 0x4bd)) | (_0x36c054 >>> (-0x1f5e + 0x1aa0 + 0x3d * 0x14))) + _0x33f406(_0x36c054) ) }) var _0x539097 = -0x2 * -0x621a4af5 + 0xc681287f + -0xec7e44b0, _0x12ada0 function _0x75d5b3(_0x5a0afa, _0x1ccbbd) { var _0x13780b = _0x5612de, _0xc312d4 = _0x5a0afa['length'], _0x102845 = _0xc312d4 << (-0x3 * -0x711 + 0x9a9 * 0x2 + -0x2883) if (_0x1ccbbd) { var _0x25438e = _0x5a0afa[_0xc312d4 - (0x1b18 + 0x1 * 0xfb6 + -0x1 * 0x2acd)] if (_0x25438e < (_0x102845 -= 0x1f * 0x62 + -0xac0 + -0x8d * 0x2) - (-0xfed + -0x8a * 0x23 + 0x22ce) || _0x25438e > _0x102845) return null _0x102845 = _0x25438e } for (var _0x41e0a1 = -0x13b + -0x1963 + -0xd4f * -0x2; _0x41e0a1 < _0xc312d4; _0x41e0a1++) _0x5a0afa[_0x41e0a1] = String['fromCharCode']( (-0x30 * -0x12 + -0x235b + -0x15 * -0x192) & _0x5a0afa[_0x41e0a1], (_0x5a0afa[_0x41e0a1] >>> (-0x1839 * -0x1 + -0x5 * -0x196 + 0x1 * -0x201f)) & (-0x2 * 0x2b3 + 0x1 * 0x19c9 + -0x1364), (_0x5a0afa[_0x41e0a1] >>> (-0x12b * 0x1 + 0xa54 * 0x1 + -0x11 * 0x89)) & (0xc36 * 0x2 + 0x2 * 0x1259 + 0x1 * -0x3c1f), (_0x5a0afa[_0x41e0a1] >>> (0x564 + 0x2325 + -0x15 * 0x1ed)) & (0x2673 + -0x1411 + -0x1163) ) var _0x5ef85e = _0x5a0afa[_0x13780b(0x24f)]('') return _0x1ccbbd ? _0x5ef85e['substring'](0x3 * -0x388 + -0xe41 + 0x18d9, _0x102845) : _0x5ef85e } function _0x183951(_0x15f4d9, _0x59200b) { var _0x4f373f = _0x5612de, _0x40761a, _0x6155ee = _0x15f4d9[_0x4f373f(0x259)], _0x21fe82 = _0x6155ee >> (0xb8d * -0x1 + -0x1 * 0x5fe + -0x1 * -0x118d) 0x4 * -0xbc + 0x12f0 + -0x1000 != ((-0x79 * 0x2 + -0xb1 * 0x16 + 0x102b) & _0x6155ee) && ++_0x21fe82, _0x59200b ? ((_0x40761a = new Array(_0x21fe82 + (0x13 * -0x65 + -0x14ef + 0xfb * 0x1d)))[_0x21fe82] = _0x6155ee) : (_0x40761a = new Array(_0x21fe82)) for (var _0x56bca4 = -0x9e0 + 0x51 * 0x1a + 0x1a6; _0x56bca4 < _0x6155ee; ++_0x56bca4) _0x40761a[_0x56bca4 >> (-0xc1b * -0x2 + -0xc2 * -0x21 + 0x1 * -0x3136)] |= _0x15f4d9['charCodeAt'](_0x56bca4) << (((0x3 * -0x4cd + -0xdfc + 0x1c66) & _0x56bca4) << (0x1 * -0x133b + 0x21a5 + 0xe67 * -0x1)) return _0x40761a } function _0x25c901(_0x431b9d) { return (0x1a1299587 + 0x91539 * -0x1c1b + -0x202b07 * -0x2ed) & _0x431b9d } function _0x38d33e(_0x1aed31, _0x212e8a, _0x427b15, _0x8fcd39, _0x4eaad6, _0x532b8e) { return ( (((_0x427b15 >>> (-0x1 * -0x1ddb + -0x20f7 + -0x3 * -0x10b)) ^ (_0x212e8a << (-0x1 * -0x407 + -0x132e + -0xf29 * -0x1))) + ((_0x212e8a >>> (-0x828 + -0xf23 + -0x9d * -0x26)) ^ (_0x427b15 << (-0xd51 + 0xc9f + 0xb6)))) ^ ((_0x1aed31 ^ _0x212e8a) + (_0x532b8e[((0x9ad + -0x763 + -0xb * 0x35) & _0x8fcd39) ^ _0x4eaad6] ^ _0x427b15)) ) } function _0x231484(_0xefe811) { var _0x13eaf5 = _0x5612de return ( _0xefe811[_0x13eaf5(0x259)] < -0xa13 + 0x1086 + -0x66f && (_0xefe811[_0x13eaf5(0x259)] = -0x1371 + -0x1ec1 * -0x1 + 0x5a6 * -0x2), _0xefe811 ) } function _0x3d58e7(_0x5e28f2, _0x468b52) { var _0x50c100 = _0x5612de, _0x7c35df, _0x4c97b3, _0x5e0270, _0x3034db, _0x56f817, _0x3084b8, _0x66df40 = _0x5e28f2[_0x50c100(0x259)], _0x5506f5 = _0x66df40 - (-0x1c76 + 0x2246 + -0x5cf) for ( _0x4c97b3 = _0x5e28f2[_0x5506f5], _0x5e0270 = 0x22ee + 0xa15 * -0x1 + -0x18d9 * 0x1, _0x3084b8 = (0x1 * 0x36f + -0x2707 + 0x2398) | Math[_0x50c100(0x1cf)](0xc72 * 0x2 + -0xe3 * 0x2b + 0xd43 + (0x1a + 0x1c2a + -0x1c10) / _0x66df40); _0x3084b8 > 0x1 * -0x1cd + -0x2476 + 0x2643; --_0x3084b8 ) { for ( _0x3034db = ((_0x5e0270 = _0x25c901(_0x5e0270 + _0x539097)) >>> (0x3b * -0x2f + 0x1290 + 0x3 * -0x293)) & (0x1533 + -0x116d + -0x3c3), _0x56f817 = 0x8 * 0x23b + -0xb89 + 0x64f * -0x1; _0x56f817 < _0x5506f5; ++_0x56f817 ) (_0x7c35df = _0x5e28f2[_0x56f817 + (0x3b * 0x5f + -0x1e1 * 0x1 + -0x1403)]), (_0x4c97b3 = _0x5e28f2[_0x56f817] = _0x25c901(_0x5e28f2[_0x56f817] + _0x38d33e(_0x5e0270, _0x7c35df, _0x4c97b3, _0x56f817, _0x3034db, _0x468b52))) ; (_0x7c35df = _0x5e28f2[-0x1570 + -0x1 * -0x385 + -0x8b * -0x21]), (_0x4c97b3 = _0x5e28f2[_0x5506f5] = _0x25c901(_0x5e28f2[_0x5506f5] + _0x38d33e(_0x5e0270, _0x7c35df, _0x4c97b3, _0x5506f5, _0x3034db, _0x468b52))) } return _0x5e28f2 } function _0x4aaf04(_0x33a7ba, _0x386196) { var _0x257c0b = _0x5612de, _0x379288, _0x247a8b, _0x334bb9, _0x2fa83f, _0x417a88, _0x2a3ae5 = _0x33a7ba[_0x257c0b(0x259)], _0x429a0d = _0x2a3ae5 - (0xc1 * -0x11 + 0x1f99 + -0xb * 0x1b5) for ( _0x379288 = _0x33a7ba[-0x1 * -0x1397 + -0x13 * -0x187 + -0x309c], _0x334bb9 = _0x25c901( Math[_0x257c0b(0x1cf)](0xe52 * -0x1 + -0x10 * 0xb + -0x34 * -0x4a + (-0x3 * -0xd9 + 0x9f * 0x2f + 0xfc4 * -0x2) / _0x2a3ae5) * _0x539097 ); -0x2e * 0x1f + 0x2223 + -0x47 * 0x67 !== _0x334bb9; _0x334bb9 = _0x25c901(_0x334bb9 - _0x539097) ) { for ( _0x2fa83f = (_0x334bb9 >>> (0x437 * 0x5 + -0xfd * 0x22 + -0xc89 * -0x1)) & (0x1 * 0x863 + 0x2267 * 0x1 + -0x2f * 0xe9), _0x417a88 = _0x429a0d; _0x417a88 > 0xfc7 + -0x788 * -0x1 + -0x15f * 0x11; --_0x417a88 ) (_0x247a8b = _0x33a7ba[_0x417a88 - (0x3b * -0x4f + 0x6d * -0xa + 0xb3c * 0x2)]), (_0x379288 = _0x33a7ba[_0x417a88] = _0x25c901(_0x33a7ba[_0x417a88] - _0x38d33e(_0x334bb9, _0x379288, _0x247a8b, _0x417a88, _0x2fa83f, _0x386196))) ; (_0x247a8b = _0x33a7ba[_0x429a0d]), (_0x379288 = _0x33a7ba[-0x1fb + 0x1952 * -0x1 + -0x1d * -0xf1] = _0x25c901( _0x33a7ba[0x7 * 0x59 + 0x5 * -0x2d2 + 0xbab] - _0x38d33e(_0x334bb9, _0x379288, _0x247a8b, -0xbac + -0x7 * 0xea + -0x606 * -0x3, _0x2fa83f, _0x386196) )) } return _0x33a7ba } function _0x532596(_0x2394ed) { var _0x22f5e8 = _0x5612de if (/^[\x00-\x7f]*$/[_0x22f5e8(0x22b)](_0x2394ed)) return _0x2394ed for ( var _0x47e840 = [], _0x5f04b8 = _0x2394ed[_0x22f5e8(0x259)], _0x150666 = -0xe97 + 0xd02 + 0x195, _0x19b157 = 0xf1c + -0x1f5 * 0x8 + 0x8c; _0x150666 < _0x5f04b8; ++_0x150666, ++_0x19b157 ) { var _0x44de53 = _0x2394ed[_0x22f5e8(0x195)](_0x150666) if (_0x44de53 < -0x1 * -0xb7b + 0x1566 + -0x2061) _0x47e840[_0x19b157] = _0x2394ed[_0x22f5e8(0x25c)](_0x150666) else { if (_0x44de53 < -0x3 * 0xcd2 + 0x1168 + 0x1 * 0x1d0e) _0x47e840[_0x19b157] = String['fromCharCode']( (0x2 * 0x579 + 0x263c * 0x1 + 0x306e * -0x1) | (_0x44de53 >> (0xca4 * -0x1 + 0x6f * 0x13 + -0x46d * -0x1)), (0x7 * -0x5 + 0x35 * 0x73 + -0x172c) | ((0xf88 * -0x1 + -0x108f * -0x1 + -0xc8) & _0x44de53) ) else { if (!(_0x44de53 < -0xaebb * 0x1 + -0x3 * -0x3a46 + 0x6f7 * 0x1f || _0x44de53 > 0x1679b * 0x1 + -0x121 * -0x15 + -0x9f51)) { if (_0x150666 + (0x15a6 + 0x1ec1 + -0x26 * 0x161) < _0x5f04b8) { var _0x254ff6 = _0x2394ed[_0x22f5e8(0x195)](_0x150666 + (-0x42 * -0x7a + 0x4 * 0x91d + -0x43e7)) if ( _0x44de53 < -0x181e4 + 0xbcbb + 0x1a129 && -0x17db * -0xf + 0xac6d * -0x1 + -0x3d8 * -0x9 <= _0x254ff6 && _0x254ff6 <= 0x159a + 0x17967 + 0x9b9 * -0x12 ) { var _0x304310 = -0x1862f + 0x1121d + 0x2 * 0xba09 + ((((0x1 * -0x140f + -0x18dd + 0x30eb) & _0x44de53) << (-0xb0 * -0x8 + 0x875 + -0x7 * 0x1fd)) | ((0x2301 + 0x171f + 0x3621 * -0x1) & _0x254ff6)) ; (_0x47e840[_0x19b157] = String[_0x22f5e8(0x1e2)]( (0x1afc * -0x1 + 0x26f4 + -0xb08) | ((_0x304310 >> (0xb * 0x14e + -0x119 * -0x1d + -0x2e1d)) & (0x1037 * 0x1 + -0x1090 + -0x2 * -0x4c)), (0x1922 + 0x4 * 0x351 + -0x25e6) | ((_0x304310 >> (0x1e93 + -0x517 + -0x1970)) & (0x2481 + 0x1591 + -0x39d3)), (-0xace * -0x1 + 0x1ef3 + -0x2941) | ((_0x304310 >> (-0xb7f * -0x3 + -0x1 * 0xe7d + -0x13fa)) & (-0x10d * -0x6 + 0x252a * 0x1 + -0x2b39)), (-0x1c61 * 0x1 + 0x1 * -0x5e7 + -0x13e * -0x1c) | ((0x13 * -0x1f9 + 0x16 * -0x164 + -0x37 * -0x13e) & _0x304310) )), ++_0x150666 continue } } throw new Error(_0x22f5e8(0x297)) } _0x47e840[_0x19b157] = String[_0x22f5e8(0x1e2)]( (-0x170b + 0x109b + 0x750) | (_0x44de53 >> (-0xbf0 * -0x2 + 0x25bc + -0x3d90)), (0x4ec + 0x1f0c + -0x8de * 0x4) | ((_0x44de53 >> (0x2 * 0x829 + -0x1b * -0x10c + -0x2c90)) & (-0x2322 + 0x19d5 + 0x34 * 0x2f)), (0x2a1 + 0x1 * 0x1ac0 + 0x1 * -0x1ce1) | ((-0xe95 + 0x1cf * 0x11 + 0x1 * -0xfeb) & _0x44de53) ) } } } return _0x47e840[_0x22f5e8(0x24f)]('') } function _0x45fbef(_0x316827, _0x2a039f) { var _0x1c80ac = _0x5612de for ( var _0x4921e2 = new Array(_0x2a039f), _0x79a402 = 0x20bd + -0x10b1 + -0x1 * 0x100c, _0x28b895 = -0xd2c + -0x1730 + 0x1 * 0x245c, _0x2bc88b = _0x316827[_0x1c80ac(0x259)]; _0x79a402 < _0x2a039f && _0x28b895 < _0x2bc88b; _0x79a402++ ) { var _0x43b518 = _0x316827[_0x1c80ac(0x195)](_0x28b895++) switch (_0x43b518 >> (-0x1342 + 0x67 * -0x53 + 0x34ab)) { case -0x410 * -0x3 + -0xd9 + -0xb57: case -0x17cb + 0x2362 + -0xb96 * 0x1: case -0x24 * 0x7f + -0x1 * -0xcfc + 0x19 * 0x32: case 0x2025 + 0x1102 + -0x3124: case 0x1b0d + 0xcb4 + 0xd3f * -0x3: case -0x11d9 + 0x9 * 0x16d + -0x1 * -0x509: case 0x79 * 0x49 + 0x1 * 0x1b8e + -0x3e09 * 0x1: case 0x26c1 + -0x2137 * 0x1 + -0x583: _0x4921e2[_0x79a402] = _0x43b518 break case 0x10f * -0x13 + 0x426 + 0x1003: case 0x164d * 0x1 + 0xb5a * 0x3 + 0x1c27 * -0x2: if (!(_0x28b895 < _0x2bc88b)) throw new Error('Unfinished\x20UTF-8\x20octet\x20sequence') _0x4921e2[_0x79a402] = (((-0x1f7 * 0xb + -0x1fa0 + 0x2ab * 0x14) & _0x43b518) << (-0x233b + 0x160e + 0xd33)) | ((-0x1e40 + 0x22b9 + -0x2 * 0x21d) & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) break case -0x2512 + -0x1595 + 0x3ab5: if (!(_0x28b895 + (0xba3 * -0x1 + -0x17dd * 0x1 + 0x1 * 0x2381) < _0x2bc88b)) throw new Error(_0x1c80ac(0x394)) _0x4921e2[_0x79a402] = (((0x247f * -0x1 + 0xec2 * 0x1 + -0x136 * -0x12) & _0x43b518) << (0x1 * 0x1bcd + -0x3dd + -0x17e4)) | (((0x1631 + -0x1058 + 0x2 * -0x2cd) & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) << (0x889 * 0x4 + 0x11c8 * 0x2 + -0x45ae)) | ((-0x698 * -0x4 + -0x2f * -0x4f + -0x28a2) & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) break case -0x85 * -0x8 + 0x1148 + -0x1561: if (!(_0x28b895 + (0x1 * -0x8f1 + -0x67 * 0x3e + 0x21e5) < _0x2bc88b)) throw new Error(_0x1c80ac(0x394)) var _0x1740ac = ((((0x1 * -0x1d4f + 0x1 * 0x24bf + -0x769) & _0x43b518) << (0xb19 + 0x4a * -0x48 + -0x3 * -0x343)) | (((-0x1ab4 + -0x205 * -0x8 + -0x3 * -0x399) & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) << (0x1e52 + -0x144b + -0x5 * 0x1ff)) | (((0x4c5 * -0x3 + 0x1 * -0x70b + 0x1599) & _0x316827[_0x1c80ac(0x195)](_0x28b895++)) << (-0xf6e + -0x37 * -0x86 + 0x239 * -0x6)) | ((0x2 * -0xc31 + 0x26b5 + -0xe14) & _0x316827[_0x1c80ac(0x195)](_0x28b895++))) - (0x1 * -0x6b6b + -0x14502 + -0x1 * -0x2b06d) if (!(0x86 * 0xd + -0x2210 + 0x1b42 <= _0x1740ac && _0x1740ac <= 0x141d1 * 0x1 + -0x3044 * -0x8b + 0x1 * -0xb76be)) throw new Error(_0x1c80ac(0x24e) + _0x1740ac['toString'](-0x959 * 0x3 + -0x50e * -0x5 + -0x1 * -0x2d5)) ; (_0x4921e2[_0x79a402++] = ((_0x1740ac >> (-0x1a89 * 0x1 + 0x125 * -0x1 + 0x1bb8)) & (-0x2 * 0x12e4 + 0xc1e + 0x1da9)) | (-0x4e * -0x332 + -0x6764 * -0x2 + -0xf004 * 0x1)), (_0x4921e2[_0x79a402] = ((0x23f0 + 0x2b * 0x11 + -0x4 * 0x8b3) & _0x1740ac) | (0xb45d + -0xd352 + 0x3 * 0x53a7)) break default: throw new Error(_0x1c80ac(0x330) + _0x43b518[_0x1c80ac(0x3ae)](-0x1f71 + 0xdc3 * -0x1 + 0x2d44)) } } return _0x79a402 < _0x2a039f && (_0x4921e2[_0x1c80ac(0x259)] = _0x79a402), String[_0x1c80ac(0x1e2)]['apply'](String, _0x4921e2) } function _0x25bfe1(_0x5ad020, _0x1001f1) { var _0xa8facb = _0x5612de for ( var _0xdb2671 = [], _0x67f891 = new Array(-0x29 * 0x169 + 0x1d * -0x3c7 + -0x6 * -0x313a), _0x3fce02 = -0x47c * -0x1 + -0xc83 + 0x2ad * 0x3, _0x47254b = 0x1010 + -0xb * 0x29 + -0xe4d, _0x4445a9 = _0x5ad020[_0xa8facb(0x259)]; _0x3fce02 < _0x1001f1 && _0x47254b < _0x4445a9; _0x3fce02++ ) { var _0x488af6 = _0x5ad020['charCodeAt'](_0x47254b++) switch (_0x488af6 >> (-0x1148 + 0xbd2 + 0x57a)) { case -0x1 * -0xb6b + 0x16f6 + -0x2261: case -0x1678 + -0x1c12 + 0x3 * 0x10d9: case 0xd01 * -0x2 + 0x2c2 + -0x1a * -0xe5: case 0x1985 + 0x49 * -0x6d + 0x593: case 0xbac + 0xd1a * 0x1 + -0x18c2: case -0x11 * -0x1 + 0x1 * -0x18bd + 0x18b1: case 0x1e6 + -0x129a * -0x1 + 0x1 * -0x147a: case -0x1 * 0xf49 + 0xed + 0xe63: _0x67f891[_0x3fce02] = _0x488af6 break case 0x30e * 0xb + 0x255b + -0x1 * 0x46e9: case 0x71 * -0xf + -0x1371 + 0x1a1d: if (!(_0x47254b < _0x4445a9)) throw new Error(_0xa8facb(0x394)) _0x67f891[_0x3fce02] = (((-0x407 * -0x5 + -0xcb5 + 0x74f * -0x1) & _0x488af6) << (-0x585 + -0xbf8 + 0x1183)) | ((-0x1 * 0x1e25 + 0x6d * -0x3b + 0x1281 * 0x3) & _0x5ad020['charCodeAt'](_0x47254b++)) break case -0x676 * -0x4 + -0x351 + -0x1679: if (!(_0x47254b + (0x1b63 + -0x5 * 0x463 + -0x573) < _0x4445a9)) throw new Error(_0xa8facb(0x394)) _0x67f891[_0x3fce02] = (((0x2dd * 0x7 + -0x15dd + 0x1e1) & _0x488af6) << (0x141c + 0x18e3 + -0x2cf3)) | (((-0x1 * -0x619 + 0x1 * 0x18bf + -0xa33 * 0x3) & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) << (0x1343 * -0x1 + -0x9 * 0x198 + 0x21a1)) | ((0x455 + -0x1ef3 + 0x1add) & _0x5ad020['charCodeAt'](_0x47254b++)) break case -0x21f + -0x13f9 * 0x1 + -0x6b * -0x35: if (!(_0x47254b + (-0xde * -0xb + 0x20cf + -0x2a57) < _0x4445a9)) throw new Error(_0xa8facb(0x394)) var _0x59357e = ((((0x1081 + -0x1b6f + 0xaf5) & _0x488af6) << (-0x1 * -0x511 + -0x45 * 0x55 + 0x11ea)) | (((0x125a * 0x2 + 0x4bd * -0x2 + -0x1afb) & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) << (0xbf4 * -0x2 + -0x1512 + 0x2d06)) | (((0x1aae + 0xd81 + -0x27f0) & _0x5ad020[_0xa8facb(0x195)](_0x47254b++)) << (0x1759 + -0x9a1 * -0x1 + 0x4c * -0x6f)) | ((0x352 * -0xb + -0xde7 + 0x32ac) & _0x5ad020[_0xa8facb(0x195)](_0x47254b++))) - (-0x57e9 + 0x19207 + -0x3a1e) if (!(0x41b * -0x7 + 0x1658 + 0x1 * 0x665 <= _0x59357e && _0x59357e <= -0xf6 * -0x7ed + -0x1bcf3b + -0x4 * -0x90c5f)) throw new Error( 'Character\x20outside\x20valid\x20Unicode\x20range:\x200x' + _0x59357e['toString'](-0x40f + -0x5 * -0x61f + 0x1c4 * -0xf) ) ; (_0x67f891[_0x3fce02++] = ((_0x59357e >> (-0x15e2 + 0x1 * -0xb51 + -0x43 * -0x7f)) & (-0x11a2 + 0xb * -0x29 + 0x7cc * 0x3)) | (0x1 * -0x3d14 + 0x159a9 + -0x1 * 0x4495)), (_0x67f891[_0x3fce02] = ((0x1 * 0x101 + -0x499 + 0x797) & _0x59357e) | (0x1dec + 0x87f7 + 0x361d)) break default: throw new Error('Bad\x20UTF-8\x20encoding\x200x' + _0x488af6[_0xa8facb(0x3ae)](-0x11 * 0x1dc + 0x1a53 + 0x559)) } if (_0x3fce02 >= -0xb3 * -0x16e + 0x1616 + 0x1a6 * -0x5b) { var _0x2ceb4e = _0x3fce02 + (0x4 * -0x8fe + 0x665 * 0x3 + 0x10ca) ; (_0x67f891[_0xa8facb(0x259)] = _0x2ceb4e), (_0xdb2671[_0xdb2671[_0xa8facb(0x259)]] = String[_0xa8facb(0x1e2)][_0xa8facb(0x207)](String, _0x67f891)), (_0x1001f1 -= _0x2ceb4e), (_0x3fce02 = -(-0x18 * -0x111 + 0x2 * 0x9e3 + -0x2d5d)) } } return ( _0x3fce02 > 0x1 * 0xb5d + -0x20a3 + 0x1546 && ((_0x67f891['length'] = _0x3fce02), (_0xdb2671[_0xdb2671[_0xa8facb(0x259)]] = String['fromCharCode'][_0xa8facb(0x207)](String, _0x67f891))), _0xdb2671['join']('') ) } function _0x31dfb5(_0x360a73, _0xe765ba) { var _0x293f34 = _0x5612de return ( (null == _0xe765ba || _0xe765ba < -0x1605 + 0xf7 * 0xe + 0x883) && (_0xe765ba = _0x360a73[_0x293f34(0x259)]), -0x6 * 0x30b + -0x1608 + 0x284a === _0xe765ba ? '' : /^[\x00-\x7f]*$/[_0x293f34(0x22b)](_0x360a73) || !/^[\x00-\xff]*$/[_0x293f34(0x22b)](_0x360a73) ? _0xe765ba === _0x360a73[_0x293f34(0x259)] ? _0x360a73 : _0x360a73[_0x293f34(0x3a7)](0x169 + 0x887 + 0x6a * -0x18, _0xe765ba) : _0xe765ba < 0x1d0d6 + 0x73e5 + -0x4 * 0x512f ? _0x45fbef(_0x360a73, _0xe765ba) : _0x25bfe1(_0x360a73, _0xe765ba) ) } function _0xdda738(_0x21d8ce, _0x4bf3f9) { var _0x46d91f = _0x5612de return null == _0x21d8ce || 0x1 * -0xab1 + -0x2567 * -0x1 + -0x1ab6 === _0x21d8ce[_0x46d91f(0x259)] ? _0x21d8ce : ((_0x21d8ce = _0x532596(_0x21d8ce)), (_0x4bf3f9 = _0x532596(_0x4bf3f9)), _0x75d5b3( _0x3d58e7( _0x183951(_0x21d8ce, !(0xad5 + 0xaa1 + -0x2 * 0xabb)), _0x231484(_0x183951(_0x4bf3f9, !(-0x106c + -0x1173 * -0x2 + -0x1279))) ), !(-0x1 * 0x2c8 + -0xc8 + 0x391) )) } function _0x4bb829(_0x1f763e, _0x47e9cd) { var _0x18b798 = _0x5612de return null == _0x1f763e || -0x12 * 0xe1 + 0x3cb * -0x5 + 0x22c9 === _0x1f763e[_0x18b798(0x259)] ? _0x1f763e : ((_0x47e9cd = _0x532596(_0x47e9cd)), _0x31dfb5( _0x75d5b3( _0x4aaf04( _0x183951(_0x1f763e, !(-0x40 * -0x16 + -0x133 * -0x1d + -0x2846)), _0x231484(_0x183951(_0x47e9cd, !(0x1e64 + 0xcee + -0x2b51))) ), !(-0x1daa + -0xbb1 + 0x295b) ) )) } function _0x39dfe4() { var _0x2fd4da = _0x5612de, _0x21e994 = '' try { window[_0x2fd4da(0x3be)] && (_0x21e994 = window[_0x2fd4da(0x3be)]['getItem']('_byted_param_sw')), (_0x21e994 && !window[_0x2fd4da(0x1dc)]) || (_0x21e994 = window['localStorage'][_0x2fd4da(0x2d8)]('_byted_param_sw')) } catch (_0x3b8cd9) { } if (_0x21e994) try { var _0x25acb5 = _0x4bb829( _0xb5350b(_0x21e994[_0x2fd4da(0x2a5)](0x19 * 0xc9 + -0x1bc8 + -0x82f * -0x1)), _0x21e994[_0x2fd4da(0x2a5)](0x2 * 0xa88 + -0x25 * -0x94 + -0x2a74, 0x2c6 * 0x5 + -0x14c6 + 0x1bc * 0x4) ) if ('on' === _0x25acb5) return !(0x527 * -0x7 + 0x7b7 + 0x1c5a) if (_0x2fd4da(0x304) === _0x25acb5) return !(0x1b29 * -0x1 + -0xd8d + 0x1 * 0x28b7) } catch (_0x1da1e4) { } return !(-0x158c + 0x10 * -0x13d + 0x1 * 0x295d) } function _0x1b4bf1() { var _0x4eb990 = _0x5612de return w_0x5c3140( _0x4eb990(0x211), { get 0x0() { var _0x448d97 = _0x4eb990 return _0x448d97(0x384) != typeof navigator ? navigator : void (-0xd95 * -0x2 + -0x1 * 0x16ed + 0x5 * -0xd9) }, get 0x1() { var _0x389269 = _0x4eb990 return _0x389269(0x384) != typeof window ? window : void (0x63e + 0xb * -0x32b + -0x1c9b * -0x1) }, get 0x2() { return _0x1db123 }, 0x3: Object, get 0x4() { return 'undefined' != typeof document ? document : void (0xe3a + 0x2499 + -0x32d3) }, get 0x5() { var _0x813809 = _0x4eb990 return _0x813809(0x384) != typeof location ? location : void (-0x1 * -0x2145 + 0x54e * -0x7 + -0x1 * -0x3dd) }, get 0x6() { return _0x176a57 }, get 0x7() { return 'undefined' != typeof history ? history : void (-0x17d + -0x1ef4 + 0x2071) }, 0x8: arguments }, this ) } function _0x532cd9() { var _0x3b3ba1 = _0x5612de return w_0x5c3140( _0x3b3ba1(0x190), { get 0x0() { return _0x176a57 }, get 0x1() { return navigator }, get 0x2() { return PluginArray }, get 0x3() { return window }, 0x4: arguments }, this ) } function _0x3391fc() { var _0x2aea9b = _0x5612de return w_0x5c3140( _0x2aea9b(0x266), { get 0x0() { return _0x12ada0 }, get 0x1() { return navigator }, 0x2: Object, get 0x3() { return window }, 0x4: arguments, 0x5: RegExp }, this ) } function _0x21fa28() { var _0x1106df = _0x5612de return w_0x5c3140( _0x1106df(0x17b), { set 0x0(_0x2b3a0b) { _0x12ada0 = _0x2b3a0b }, 0x1: Object, get 0x2() { return window }, 0x3: arguments }, this ) } function _0x49b1d7(_0x4f4807) { var _0x4f1753 = _0x5612de return w_0x5c3140( _0x4f1753(0x171), { get 0x0() { return _0x1230e7 }, get 0x1() { return indexedDB }, get 0x2() { return _0xf8ccf1 }, get 0x3() { return window }, get 0x4() { return DOMException }, get 0x5() { return _0x176a57 }, get 0x6() { return _0x6caf }, 0x7: arguments, 0x8: _0x4f4807 }, this ) } function _0x462256() { var _0x1ed1aa = _0x5612de return w_0x5c3140( _0x1ed1aa(0x163), { get 0x0() { return _0x176a57 }, get 0x1() { return document }, get 0x2() { return navigator }, 0x3: arguments, 0x4: RegExp }, this ) } function _0x3cee0e() { var _0x5f1e22 = _0x5612de return w_0x5c3140( _0x5f1e22(0x2dd), { get 0x0() { return navigator }, get 0x1() { return window }, 0x2: arguments, 0x3: RegExp }, this ) } function _0x1f9824() { var _0x1d4f72 = _0x5612de, _0x5821af = '' if (_0x6caf['PLUGIN']) _0x5821af = _0x6caf[_0x1d4f72(0x354)] else { for ( var _0x580f96 = [], _0x3ca683 = navigator[_0x1d4f72(0x1ba)] || [], _0x15f771 = 0x389 * 0x5 + -0x2a * -0xe2 + -0x36c1; _0x15f771 < -0xe3b * 0x1 + 0x1a76 + -0x6 * 0x209; _0x15f771++ ) try { for ( var _0x5a4f6c = _0x3ca683[_0x15f771], _0x3a1f6 = [], _0x1a6da9 = -0x869 + -0x111 * 0x14 + -0x1dbd * -0x1; _0x1a6da9 < _0x5a4f6c[_0x1d4f72(0x259)]; _0x1a6da9++ ) _0x5a4f6c[_0x1d4f72(0x37c)](_0x1a6da9) && _0x3a1f6[_0x1d4f72(0x36e)](_0x5a4f6c['item'](_0x1a6da9)[_0x1d4f72(0x1ab)]) var _0x1ae7c8 = _0x5a4f6c[_0x1d4f72(0x341)] + '' _0x5a4f6c['version'] && (_0x1ae7c8 += _0x5a4f6c[_0x1d4f72(0x2c1)] + ''), (_0x1ae7c8 += _0x5a4f6c['filename'] + ''), (_0x1ae7c8 += _0x3a1f6[_0x1d4f72(0x24f)]('')), _0x580f96['push'](_0x1ae7c8) } catch (_0x4e31c6) { } ; (_0x5821af = _0x580f96[_0x1d4f72(0x24f)]('##')), (_0x6caf[_0x1d4f72(0x354)] = _0x5821af) } return _0x5821af[_0x1d4f72(0x2a5)](-0x1 * 0x26c + -0x1e2f + 0x209b, -0x26ff + 0x1b6e * 0x1 + 0xf91) } function _0x30412e() { var _0x5a747f = _0x5612de, _0x5640f8 = [] try { var _0x3405cb = navigator[_0x5a747f(0x1ba)] if (_0x3405cb) { for (var _0x53b06e = -0x8aa + 0x341 + 0x115 * 0x5; _0x53b06e < _0x3405cb[_0x5a747f(0x259)]; _0x53b06e++) for (var _0xa74ec6 = -0x1829 + 0x1f9c + -0x773; _0xa74ec6 < _0x3405cb[_0x53b06e][_0x5a747f(0x259)]; _0xa74ec6++) { var _0x2bcc6c = [ _0x3405cb[_0x53b06e][_0x5a747f(0x19e)], _0x3405cb[_0x53b06e][_0xa74ec6][_0x5a747f(0x1ab)], _0x3405cb[_0x53b06e][_0xa74ec6][_0x5a747f(0x169)] ][_0x5a747f(0x24f)]('|') _0x5640f8['push'](_0x2bcc6c) } } } catch (_0x11c0f4) { } return _0x5640f8 } function _0x28e2ec() { var _0x3301ae = _0x5612de return w_0x5c3140( _0x3301ae(0x1a6), { get 0x0() { return navigator }, get 0x1() { return _0x1f9824 }, get 0x2() { return window }, 0x3: arguments }, this ) } function _0x5863d1() { var _0x247350 = _0x5612de return w_0x5c3140( _0x247350(0x21c), { get 0x0() { return _0x462335 }, get 0x1() { return _0x39dfe4 }, get 0x2() { return _0x1b4bf1 }, get 0x3() { return _0x53b77d }, get 0x4() { return _0x49b1d7 }, get 0x5() { return _0x3ed707 }, get 0x6() { return _0x532cd9 }, get 0x7() { return _0x3391fc }, get 0x8() { return _0x462256 }, get 0x9() { return _0x3cee0e }, get 0xa() { return _0x28e2ec }, get 0xb() { return _0x6caf }, 0xc: arguments }, this ) } function _0x2a900b(_0x29489b) { var _0x3163ac = _0x5612de for ( var _0x2edc36 = Object[_0x3163ac(0x17f)](_0x29489b), _0x4da10f = -0x26c9 + -0x11f1 * -0x1 + 0x14d8, _0x26fc90 = _0x2edc36[_0x3163ac(0x259)] - (0x1cea + -0x5 * 0x2f5 + 0x8 * -0x1c4); _0x26fc90 >= -0x2 * -0x397 + 0x17ce + -0x1efc; _0x26fc90-- ) { _0x4da10f = ((_0x29489b[_0x2edc36[_0x26fc90]] ? 0x455 * 0x9 + 0x1715 + -0x3e11 : -0x1 * -0x22f7 + 0x1f6c * 0x1 + -0x203 * 0x21) << (_0x2edc36[_0x3163ac(0x259)] - _0x26fc90 - (-0x64c * -0x6 + -0x163 + -0x224 * 0x11))) | _0x4da10f } return _0x4da10f } function _0x246aeb(_0x1b02ae, _0x32abc9) { var _0x172517 = _0x5612de for (var _0x4d2e6c = 0x1e44 + 0x2 * 0x443 + 0x2 * -0x1365; _0x4d2e6c < _0x32abc9[_0x172517(0x259)]; _0x4d2e6c++) _0x1b02ae = ((-0xa15f + -0x1a803 + 0x349a1) * _0x1b02ae + _0x32abc9[_0x172517(0x195)](_0x4d2e6c)) >>> (-0x2c6 + 0x2 * -0x126c + 0x279e) return _0x1b02ae } function _0x184783(_0x9867bc, _0x21d0e6) { var _0x25b989 = _0x5612de for (var _0x21703e = -0xa6 * -0x1 + 0xbf * -0x5 + -0x315 * -0x1; _0x21703e < _0x21d0e6[_0x25b989(0x259)]; _0x21703e++) _0x9867bc = ((-0x6275 + 0xd966 + -0x5f * -0x172) * (_0x9867bc ^ _0x21d0e6['charCodeAt'](_0x21703e))) >>> (-0xf * 0x1a + 0x7 * -0x543 + 0x443 * 0x9) return _0x9867bc } function _0xf119da(_0x57529f, _0x19340f) { var _0x1de06d = _0x5612de for (var _0x3e7b02 = 0x45a * 0x1 + -0xe5d * 0x2 + 0x1860; _0x3e7b02 < _0x19340f[_0x1de06d(0x259)]; _0x3e7b02++) { var _0x25af5d = _0x19340f[_0x1de06d(0x195)](_0x3e7b02) if ( _0x25af5d >= -0x12321 + 0x417 * -0xa + 0x22407 && _0x25af5d <= 0x92d4 + 0xb6fd + -0x6dd2 && _0x3e7b02 < _0x19340f[_0x1de06d(0x259)] ) { var _0xfb40a0 = _0x19340f['charCodeAt'](_0x3e7b02 + (0x688 * 0x4 + 0x145 * 0x17 + -0x3752)) ; -0xa62a + -0x10ba7 + -0x5d67 * -0x7 == ((0xfbaf + 0x1ce63 + -0x1ce12) & _0xfb40a0) && ((_0x25af5d = (((-0x9fe * 0x1 + 0x2 * -0xf33 + 0x2c63) & _0x25af5d) << (-0x86d * 0x4 + -0x211 * 0x9 + -0x1 * -0x3457)) + ((-0x1b17 + 0xb6c + 0x13aa) & _0xfb40a0) + (0x2 * 0xab9c + -0x18f24 + -0x4 * -0x4dfb)), (_0x3e7b02 += -0x1e31 + -0xa * 0x38b + -0x150 * -0x32)) } _0x57529f = ((-0x3a * 0x7e4 + -0x3827 * -0x2 + 0x151 * 0x1c9) * _0x57529f + _0x25af5d) >>> (0x3e7 + -0x1 * -0x5e7 + -0x9ce) } return _0x57529f } function _0x53f850(_0x450920) { var _0x30ac3f = _0x5612de, _0x4eeea4 = _0x450920 || '' return (_0x4eeea4 = (_0x4eeea4 = -(-0x13 * -0x5a + 0xb2f + -0x11dc) !== (_0x4eeea4 = _0x4eeea4[_0x30ac3f(0x377)](/(http:\/\/|https:\/\/|\/\/)?[^\/]*/, ''))['indexOf']('?') ? _0x4eeea4[_0x30ac3f(0x3a7)](-0x819 * 0x3 + 0x1d1c + -0x9 * 0x89, _0x4eeea4[_0x30ac3f(0x2c5)]('?')) : _0x4eeea4) || '/') } function _0x446110(_0xc80785) { var _0x5bf664 = _0x5612de, _0x471548 = _0xc80785 || '', _0x2cf363 = _0x471548[_0x5bf664(0x1c2)](/[?](\w+=.*&?)*/), _0x137237 = (_0x471548 = _0x2cf363 ? _0x2cf363[-0x2292 + -0x4 * 0x520 + 0x173 * 0x26][_0x5bf664(0x3a7)](0x112 * 0x11 + 0x61 + -0x2 * 0x949) : '') ? _0x471548[_0x5bf664(0x342)]('&') : null, _0x290269 = {} if (_0x137237) { for (var _0x15cd4c = 0xd54 + -0x49f + 0x2e7 * -0x3; _0x15cd4c < _0x137237[_0x5bf664(0x259)]; _0x15cd4c++) _0x290269[_0x137237[_0x15cd4c]['split']('=')[0x65c + 0x3f8 * -0x2 + 0x194]] = _0x137237[_0x15cd4c][_0x5bf664(0x342)]('=')[0x15bb * -0x1 + -0x50b * 0x4 + 0x29e8] } return _0x290269 } function _0x3a1cf3(_0x8af04, _0xe4b509) { var _0x28f81c = _0x5612de if (!_0x8af04 || '{}' === JSON[_0x28f81c(0x1e6)](_0x8af04)) return {} for ( var _0x257ee8 = Object[_0x28f81c(0x17f)](_0x8af04)['sort'](), _0x24c84a = {}, _0x4bfbcd = -0x1 * 0x21fb + -0x25 * -0x16 + 0x1ecd; _0x4bfbcd < _0x257ee8[_0x28f81c(0x259)]; _0x4bfbcd++ ) _0x24c84a[_0x257ee8[_0x4bfbcd]] = _0xe4b509 ? _0x8af04[_0x257ee8[_0x4bfbcd]] + '' : _0x8af04[_0x257ee8[_0x4bfbcd]] return _0x24c84a } function _0x20b77a(_0x3745f1) { var _0x211da5 = _0x5612de return Array[_0x211da5(0x2af)](_0x3745f1) ? _0x3745f1['map'](_0x20b77a) : _0x3745f1 instanceof Object ? Object[_0x211da5(0x17f)](_0x3745f1) [_0x211da5(0x38e)]() [_0x211da5(0x376)](function (_0x4b45b3, _0x5188a8) { return (_0x4b45b3[_0x5188a8] = _0x20b77a(_0x3745f1[_0x5188a8])), _0x4b45b3 }, {}) : _0x3745f1 } function _0x483e03(_0x44c650) { var _0x498394 = _0x5612de if (!_0x44c650 || '{}' === JSON[_0x498394(0x1e6)](_0x44c650)) return '' for ( var _0x52341a = Object['keys'](_0x44c650)['sort'](), _0x3c151a = '', _0x4f5c3f = -0xefc + 0x25ba + 0x29 * -0x8e; _0x4f5c3f < _0x52341a[_0x498394(0x259)]; _0x4f5c3f++ ) _0x3c151a += [_0x52341a[_0x4f5c3f]] + '=' + _0x44c650[_0x52341a[_0x4f5c3f]] + '&' return _0x3c151a } function _0x4bae98() { var _0x33d77a = _0x5612de try { return !!window[_0x33d77a(0x3be)] } catch (_0x2002b2) { return !(0xcab + -0xcff + 0x2 * 0x2a) } } function _0x275e5a() { try { return !!window['localStorage'] } catch (_0x2df8fe) { return !(-0x1ff * -0xd + 0x1cf1 * -0x1 + -0x17f * -0x2) } } function _0x4fdb47() { var _0x34b6b1 = _0x5612de try { return !!window[_0x34b6b1(0x218)] } catch (_0x3b6071) { return !(0xedb * -0x1 + 0x41b * -0x5 + -0x2 * -0x11b1) } } function _0x1afbc2() { return _0x5af46a(_0x4fdb47()) + _0x5af46a(_0x275e5a()) + _0x5af46a(_0x4bae98()) } function _0xc6f828(_0x23a724) { var _0x198ea0 = _0x5612de, _0x112670, _0x256bde = document[_0x198ea0(0x260)](_0x198ea0(0x24d)) ; (_0x256bde[_0x198ea0(0x302)] = 0x1813 * -0x1 + 0x1f94 + 0x751 * -0x1), (_0x256bde[_0x198ea0(0x245)] = -0x205f + 0x4f6 + -0x1b79 * -0x1) var _0xa760ad = _0x256bde['getContext']('2d') ; (_0xa760ad[_0x198ea0(0x18f)] = '14px\x20serif'), _0xa760ad[_0x198ea0(0x196)]('龘ฑภ경', 0x2162 * 0x1 + 0xbbb + -0x2d1b, -0x1 * -0x138a + -0x164e + 0x90 * 0x5), (_0xa760ad[_0x198ea0(0x3a0)] = -0xa67 + 0x7c * 0x39 + 0x103 * -0x11), (_0xa760ad[_0x198ea0(0x268)] = 0x22cf * 0x1 + -0x4d3 + 0x5 * -0x5ff), (_0xa760ad[_0x198ea0(0x340)] = _0x198ea0(0x21b)), _0xa760ad['arc']( -0x1 * -0x5dd + -0x6de + 0x109, -0x336 * 0x4 + -0x167a + 0x712 * 0x5, -0x7c8 + 0xb80 + -0x3b * 0x10, 0x411 + 0x38 * -0xaa + 0x3d * 0x8b, 0x7f * -0x20 + 0x11bb + -0x1d9 ), _0xa760ad['stroke'](), (_0x112670 = _0x256bde[_0x198ea0(0x239)]()) for (var _0x367ff8 = 0xfa7 * -0x1 + -0x53 * 0x6d + 0x32fe; _0x367ff8 < 0x17b + -0x1b0e * 0x1 + 0x2b * 0x99; _0x367ff8++) _0x23a724 = ((0x1675 * -0xc + -0xe91a + 0x2f6d5) * _0x23a724 + _0x112670['charCodeAt'](_0x23a724 % _0x112670[_0x198ea0(0x259)])) >>> (-0x44 + 0xfa0 * -0x2 + -0x1f84 * -0x1) return _0x23a724 } var _0x37a93a = -0x1b3b + 0x2136 + -0x1 * 0x5fb function _0x18b4be() { var _0x4d1378 = _0x5612de try { return ( _0x37a93a || (_0x462335[_0x4d1378(0x219)] ? -(-0x1 * 0x19d5 + -0x1e5d + 0x3833) : (_0x37a93a = _0xc6f828(0x15 * 0x144d79ba + 0x8831fd63 + -0x153df3ab6))) ) } catch (_0x3c9d0d) { return -(0x1e58 + -0x26 * -0xcb + 0x3c79 * -0x1) } } function _0x1a39c4() { if (_0x37a93a) return _0x37a93a _0x37a93a = _0xc6f828(-0x361cdc2a * -0x5 + 0x17c5 * 0xb369b + -0x2f7 * 0x6a0ca6) } var _0x45ece5 = { fpProfileUrl: _0x5612de(0x172) } function _0x130155() { var _0x5e9262 = _0x5612de, _0x380346 = window[_0x5e9262(0x328)] return _0x380346[_0x5e9262(0x302)] + '_' + _0x380346[_0x5e9262(0x245)] + '_' + _0x380346[_0x5e9262(0x17e)] } function _0x2a76f8() { var _0x1d2b79 = _0x5612de, _0xa8cb6a = window['screen'] return _0xa8cb6a[_0x1d2b79(0x38a)] + '_' + _0xa8cb6a[_0x1d2b79(0x276)] } function _0x3da279() { return new Promise(function (_0x2a10ed) { var _0x7d3f27 = w_0x25f3 if (_0x7d3f27(0x1b2) in navigator) try { navigator['getBattery']()[_0x7d3f27(0x1ed)](function (_0x13ff1d) { var _0x479b99 = _0x7d3f27 _0x2a10ed( _0x13ff1d[_0x479b99(0x3ac)] + '_' + _0x13ff1d[_0x479b99(0x2b0)] + '_' + _0x13ff1d[_0x479b99(0x353)] + '_' + _0x13ff1d[_0x479b99(0x213)] ) }) } catch (_0x2c28b8) { _0x2a10ed('') } else _0x2a10ed('') }) } var _0x47ec2a = {} function _0x299f3a() { var _0x2531b6 = _0x5612de, _0x1a8a34, _0x2e0843 = _0x2531b6(0x33b), _0x29ea20 = -0x12a4 + 0x30b + 0xf99 void (-0x2b * 0xa + -0x1d8d + 0x1f3b) !== navigator[_0x2e0843] && (_0x29ea20 = navigator[_0x2e0843]) try { document[_0x2531b6(0x188)](_0x2531b6(0x240)), (_0x1a8a34 = !(-0x1f61 + 0x19 * 0x22 + 0x1c0f)) } catch (_0x3992e0) { _0x1a8a34 = !(0x17 * -0x5d + -0x1 * 0x209 + 0x377 * 0x3) } var _0x11190a = _0x2531b6(0x1ea) in window return ( Object[_0x2531b6(0x2a0)](_0x47ec2a, { maxTouchPoints: _0x29ea20, touchEvent: _0x1a8a34, touchStart: _0x11190a }), _0x29ea20 + '_' + _0x1a8a34 + '_' + _0x11190a ) } function _0xbe842b() { return _0x47ec2a } function _0x4649a1() { var _0x3b6f20 = _0x5612de, _0x4256a7 = new Date() _0x4256a7[_0x3b6f20(0x22d)](-0x1477 + 0xde4 * -0x1 + 0xb74 * 0x3), _0x4256a7[_0x3b6f20(0x294)](-0x360 + -0x263d + 0x29a2) var _0x213a03 = -_0x4256a7[_0x3b6f20(0x237)]() _0x4256a7[_0x3b6f20(0x294)](-0x9b5 + 0x5 * 0x77e + -0x2 * 0xddb) var _0x5a2621 = -_0x4256a7[_0x3b6f20(0x237)]() return Math['min'](_0x213a03, _0x5a2621) } function _0x487576() { var _0x5557a1 = _0x5612de if (_0x6caf[_0x5557a1(0x2db)]) return _0x6caf[_0x5557a1(0x2db)] try { var _0x4f28ec = document[_0x5557a1(0x260)](_0x5557a1(0x24d))[_0x5557a1(0x2f9)]('webgl'), _0x36473d = _0x4f28ec['getExtension'](_0x5557a1(0x375)), _0x3ebb8d = _0x4f28ec[_0x5557a1(0x383)](_0x36473d['UNMASKED_VENDOR_WEBGL']) + '/' + _0x4f28ec['getParameter'](_0x36473d[_0x5557a1(0x39e)]) return (_0x6caf[_0x5557a1(0x2db)] = _0x3ebb8d), _0x3ebb8d } catch (_0x2b9fa5) { return '' } } function _0x4f323e() { var _0x2968a5 = _0x5612de, _0xf55c22 = [_0x2968a5(0x27b), 'sans-serif', _0x2968a5(0x1fb)], _0x3ed5f8 = {}, _0x2fef11 = {} if (!document[_0x2968a5(0x189)]) return '0' for (var _0x6f70bc = -0x2271 + 0x2f * 0x72 + 0xd83, _0x3e66d7 = _0xf55c22; _0x6f70bc < _0x3e66d7['length']; _0x6f70bc++) { var _0x189f91 = _0x3e66d7[_0x6f70bc], _0x2bf145 = document[_0x2968a5(0x260)](_0x2968a5(0x1f7)) ; (_0x2bf145['innerHTML'] = _0x2968a5(0x2a3)), (_0x2bf145['style'][_0x2968a5(0x362)] = '72px'), (_0x2bf145['style']['fontFamily'] = _0x189f91), document[_0x2968a5(0x189)][_0x2968a5(0x26c)](_0x2bf145), (_0x3ed5f8[_0x189f91] = _0x2bf145[_0x2968a5(0x2ee)]), (_0x2fef11[_0x189f91] = _0x2bf145['offsetHeight']), document[_0x2968a5(0x189)][_0x2968a5(0x30d)](_0x2bf145) } var _0x4f59cf, _0x4abd0f = [ 'Trebuchet\x20MS', _0x2968a5(0x177), _0x2968a5(0x25d), 'Segoe\x20UI', _0x2968a5(0x321), _0x2968a5(0x192), 'MT\x20Extra', _0x2968a5(0x3a9), _0x2968a5(0x28e), _0x2968a5(0x346), 'Meiryo', _0x2968a5(0x247), _0x2968a5(0x1ef), _0x2968a5(0x1d8), 'IrisUPC', 'Palatino', 'Colonna\x20MT', 'Playbill', _0x2968a5(0x1f4), _0x2968a5(0x288), _0x2968a5(0x1f2), _0x2968a5(0x38d), 'OPTIMA', _0x2968a5(0x2d9), _0x2968a5(0x348), _0x2968a5(0x2b3), 'Savoye\x20LET', _0x2968a5(0x3c5), _0x2968a5(0x21e) ] _0x4f59cf = -0x255b * -0x1 + -0x1 * -0x139d + -0x38f8 for (var _0x16c300 = -0x1 * 0xc3e + -0x20ff + 0x2d3d; _0x16c300 < _0x4abd0f[_0x2968a5(0x259)]; _0x16c300++) { var _0x2c3be4, _0x37b937 = _0x350075(_0xf55c22) try { for (_0x37b937['s'](); !(_0x2c3be4 = _0x37b937['n']())[_0x2968a5(0x1e3)];) { var _0x400340 = _0x2c3be4['value'], _0x200821 = document[_0x2968a5(0x260)]('span') ; (_0x200821[_0x2968a5(0x36a)] = _0x2968a5(0x2a3)), (_0x200821['style'][_0x2968a5(0x362)] = _0x2968a5(0x283)), (_0x200821[_0x2968a5(0x280)]['fontFamily'] = _0x4abd0f[_0x16c300] + ',' + _0x400340), document['body'][_0x2968a5(0x26c)](_0x200821) var _0x533f71 = _0x200821[_0x2968a5(0x2ee)] !== _0x3ed5f8[_0x400340] || _0x200821[_0x2968a5(0x2a4)] !== _0x2fef11[_0x400340] if ((document[_0x2968a5(0x189)][_0x2968a5(0x30d)](_0x200821), _0x533f71)) { _0x16c300 < -0x45 * -0x8a + -0x7a9 + -0x1d6b && (_0x4f59cf |= (-0x239 + 0x3 * -0x458 + 0xf42) << _0x16c300) break } } } catch (_0x5c1c6e) { _0x37b937['e'](_0x5c1c6e) } finally { _0x37b937['f']() } } return _0x4f59cf[_0x2968a5(0x3ae)](-0xe97 + -0x183c + -0x1 * -0x26e3) } function _0x5090f5() { var _0x458c87 = _0x5612de try { new WebSocket(_0x458c87(0x199)) } catch (_0x34e866) { return _0x34e866[_0x458c87(0x312)] } } function _0x468d57() { var _0x2ef0c5 = _0x5612de return eval[_0x2ef0c5(0x3ae)]()[_0x2ef0c5(0x259)] } function _0x5bbaf0() { var _0x5ec561 = _0x5612de, _0x5971d6 = window['RTCPeerConnection'] || window[_0x5ec561(0x2e0)] || window[_0x5ec561(0x19a)], _0x5aac87 = [] return new Promise(function (_0x4e6ec1) { var _0x5af634 = _0x5ec561 ; (_0x176a57() || navigator[_0x5af634(0x229)][_0x5af634(0x202)]()[_0x5af634(0x2c5)](_0x5af634(0x20e)) > -0x707 + -0x106 * 0x10 + -0x1 * -0x1767) && _0x4e6ec1('') try { if (_0x5971d6 && 'function' == typeof _0x5971d6) { var _0xadabb6 = new _0x5971d6({ iceServers: [ { urls: _0x5af634(0x27c) } ] }), _0x4405e6 = function () { }, _0x4de1d1 = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/ ; (_0xadabb6[_0x5af634(0x1eb)] = function () { var _0x374eb0 = _0x5af634 _0x374eb0(0x162) === _0xadabb6['iceGatheringState'] && (_0xadabb6[_0x374eb0(0x27a)](), (_0xadabb6 = null)) }), (_0xadabb6['onicecandidate'] = function (_0x4e2717) { var _0x18e62e = _0x5af634 if (_0x4e2717 && _0x4e2717[_0x18e62e(0x227)] && _0x4e2717[_0x18e62e(0x227)][_0x18e62e(0x227)]) { if ('' === _0x4e2717['candidate'][_0x18e62e(0x227)]) return var _0x1d1cd1 = _0x4de1d1['exec'](_0x4e2717[_0x18e62e(0x227)][_0x18e62e(0x227)]) if (null !== _0x1d1cd1 && _0x1d1cd1[_0x18e62e(0x259)] > -0x1675 * 0x1 + -0x19 * 0xdd + 0x19 * 0x1c3) { var _0xbaa956 = _0x1d1cd1[-0x1bdd * 0x1 + 0x13 * -0x1df + -0x11 * -0x3bb] ; -(0x1 * -0x12c1 + -0xa * 0x38c + -0x4ee * -0xb) === _0x5aac87[_0x18e62e(0x2c5)](_0xbaa956) && _0x5aac87[_0x18e62e(0x36e)](_0xbaa956) } } else _0x4e6ec1(_0x5aac87[_0x18e62e(0x24f)]()) }), _0xadabb6[_0x5af634(0x1e5)]('') // setTimeout(function () { // var _0x36b72e = _0x5af634; // _0x4e6ec1(_0x5aac87[_0x36b72e(0x24f)]()); // }, 0x2205 * 0x1 + 0x1d4 * -0x10 + -0x67 * 0x7); var _0x38a358 = _0xadabb6[_0x5af634(0x2f5)]() _0x38a358 instanceof Promise ? _0x38a358[_0x5af634(0x1ed)](function (_0x33e26c) { return _0xadabb6['setLocalDescription'](_0x33e26c) })[_0x5af634(0x1ed)](_0x4405e6) : _0xadabb6['createOffer'](function (_0x1c6e51) { _0xadabb6['setLocalDescription'](_0x1c6e51, _0x4405e6, _0x4405e6) }, _0x4405e6) } else _0x4e6ec1('') } catch (_0x31debb) { _0x4e6ec1('') } }) } function _0x2e02ca() { var _0x74cdcb = _0x5612de return _0x74cdcb(0x3af)[_0x74cdcb(0x377)](/[xy]/g, function (_0x5790dd) { var _0x52f0b5 = _0x74cdcb, _0x2eeaf3 = ((0x506 + -0x85c + -0x2 * -0x1b3) * Math[_0x52f0b5(0x18e)]()) | (0xbb9 * -0x1 + 0x1 * 0x9dd + 0x1dc) return ( 'x' == _0x5790dd ? _0x2eeaf3 : ((-0xd1f * 0x1 + 0x1df6 + -0x1 * 0x10d4) & _0x2eeaf3) | (0x182d + -0x10 * 0x262 + -0xdfb * -0x1) )[_0x52f0b5(0x3ae)](0x1a65 + 0x3 * 0x17a + 0x13b * -0x19) }) } function _0x2e2fa0(_0x1a6938) { var _0x5aaa98 = _0x5612de return ( -0x14 * 0x1df + 0x649 + 0x1f45 === _0x1a6938[_0x5aaa98(0x259)] && _0x246aeb( -0x21ad + 0x819 * -0x1 + 0x29c6, _0x1a6938[_0x5aaa98(0x1b0)](-0x1a55 * 0x1 + 0x1279 + 0x7dc, 0x31b + -0xcb4 * -0x1 + -0xfaf) ) [_0x5aaa98(0x3ae)]() ['substring'](0x17cc + 0x1 * -0xd19 + -0x3 * 0x391, -0x1ff * 0x1 + 0x2579 + -0x1c6 * 0x14) === _0x1a6938[_0x5aaa98(0x1b0)](0x1746 + 0x7b8 + -0x1ede, -0x369 * -0x2 + -0x5e5 * 0x4 + 0xbc * 0x17) ) } function _0x178d7c() { var _0x4d5814 = _0x5612de, _0x2d4341 = _0x24dc34(_0x4d5814(0x262)) return ( (_0x2d4341 && _0x2e2fa0(_0x2d4341)) || _0x1f42cb( _0x4d5814(0x262), (_0x2d4341 = ((_0x2d4341 = _0x2e02ca()) + _0x246aeb(0x17 * 0x12d + -0x6 * 0x3f7 + -0x341, _0x2d4341))[_0x4d5814(0x1b0)]( 0x2d1 * -0xd + 0x3a * -0x7c + 0x40b5, 0x188e + 0x13 * -0x127 + -0x287 )) ), _0x2d4341 ) } function _0x3c0a68(_0x449fe8, _0x5ede0c) { var _0x40bd5b = _0x5612de, _0x401085 = null try { _0x401085 = document['getElementsByTagName'](_0x40bd5b(0x221))[-0x2581 + 0x844 + -0x1d3d * -0x1] } catch (_0x599ca4) { _0x401085 = document['body'] } if (null !== _0x401085) { var _0x3a3665 = document[_0x40bd5b(0x260)](_0x40bd5b(0x361)), _0x215422 = '_' + parseInt((0x3df0 + 0x13d + -0x181d) * Math['random'](), 0x1 * -0x2141 + -0x1 * -0xf82 + 0x11c9) + '_' + new Date()[_0x40bd5b(0x16d)]() ; (_0x449fe8 += _0x40bd5b(0x1be) + _0x215422), (_0x3a3665[_0x40bd5b(0x16b)] = _0x449fe8), (window[_0x215422] = function (_0x1efd79) { var _0x4afb72 = _0x40bd5b try { _0x5ede0c(_0x1efd79), _0x401085[_0x4afb72(0x30d)](_0x3a3665), delete window[_0x215422] } catch (_0xf98f95) { } }), _0x401085[_0x40bd5b(0x26c)](_0x3a3665) } } function _0x4072ad(_0x18cd85) { return w_0x5c3140( '484e4f4a403f524300022c395eafc0a4000000004a04440d00000030110104324700040700004202110100030443011400011100010211010102110102110104110001430207000143021842000200404f4c4d4a4b484946474445424340415e5f5c5d5a5b58595657546f6c6d6a6b686966676465626360617e7f7c7d7a7b78797677743e3f3c3d3a3b383936372320', { get 0x0() { return _0x325f58 }, get 0x1() { return _0x328bde }, get 0x2() { return _0xdda738 }, 0x3: arguments, 0x4: _0x18cd85 }, this ) } function _0x5c0cdd(_0x380d2b, _0x1c644a) { var _0x349270 = _0x5612de if (_0x1c644a) { for ( var _0x25fd23 = -0xbdc + -0xd78 * -0x2 + -0xf14, _0x2c655d = -0x1 * -0xbdb + 0xc2 + -0xc9d; _0x2c655d < _0x380d2b[_0x349270(0x259)]; _0x2c655d++ ) _0x380d2b[_0x2c655d]['p'] && (_0x380d2b[_0x2c655d]['r'] = _0x1c644a[_0x25fd23++]) } var _0x20da32 = '' _0x380d2b[_0x349270(0x254)](function (_0x564ece) { _0x20da32 += _0x5af46a(_0x564ece['r']) + '^^' }), (_0x20da32 += _0x30c916()) var _0x2803a3 = _0x2e02ca(), _0x273650 = Math[_0x349270(0x1cf)](_0x2803a3[_0x349270(0x195)](0x127a + 0x22e0 + -0x3557 * 0x1) / (0x1 * 0x199f + -0xab4 + -0x1 * 0xee3)) + (_0x2803a3[_0x349270(0x195)](-0x15 * 0xca + -0x1ff6 * -0x1 + 0x1 * -0xf61) % (-0x1085 + -0x553 + 0x15e0)), _0x102025 = _0x2803a3['substring'](0x1 * -0x1ebf + 0x13a1 + 0x1e * 0x5f, 0x5c7 + -0x5a5 + -0x5 * 0x6 + _0x273650) _0x20da32 = _0x328bde(_0xdda738(_0x20da32, _0x102025) + _0x2803a3) var _0x197e34 = _0x45ece5['fpProfileUrl'] _0x3c0a68((_0x197e34 += _0x349270(0x173) + encodeURIComponent(_0x20da32) + '&'), function (_0x5b4c95) { var _0x3c0c48 = _0x349270 0x1db6 + -0x21d * 0x1 + -0x1b99 == _0x5b4c95[_0x3c0c48(0x356)] && _0x5b4c95['fp'] && ((_0x462335[_0x3c0c48(0x35f)] = _0x5b4c95['fp']), (_0x462335[_0x3c0c48(0x363)] = _0x4072ad(_0x5b4c95['fp'])), _0x1f42cb('tt_scid', _0x5b4c95['fp'])) }) } function _0x1c3b6d(_0x20f8c9) { var _0x596053 = _0x5612de return w_0x5c3140( _0x596053(0x242), { get 0x0() { return navigator }, get 0x1() { return window }, get 0x2() { return document }, get 0x3() { return _0x30c916 }, get 0x4() { return _0x1afbc2 }, get 0x5() { return _0x18b4be }, get 0x6() { return _0x130155 }, get 0x7() { return _0x2a76f8 }, get 0x8() { return _0x3da279 }, get 0x9() { return _0x299f3a }, get 0xa() { return _0x4649a1 }, get 0xb() { return _0x487576 }, get 0xc() { return _0x4f323e }, get 0xd() { return _0x1f9824 }, get 0xe() { return _0x24dc34 }, get 0xf() { return _0x5090f5 }, get 0x10() { return _0x468d57 }, get 0x11() { return _0x5bbaf0 }, get 0x12() { return _0x45b94b }, get 0x13() { return _0x178d7c }, get 0x14() { return _0x5af46a }, 0x15: Promise, get 0x16() { return _0x5c0cdd }, 0x17: arguments, 0x18: _0x20f8c9 }, this ) } function _0x20cbf3(_0x38a8fe, _0x406d4b, _0x2e7a9b) { var _0x1b116c = _0x5612de return w_0x5c3140( _0x1b116c(0x233), { 0x0: String, 0x1: Date, get 0x2() { return _0x45b94b }, get 0x3() { return _0x184783 }, get 0x4() { return location }, 0x5: parseInt, get 0x6() { return _0x5863d1 }, 0x7: JSON, get 0x8() { return _0xf119da }, get 0x9() { return _0x3a1cf3 }, get 0xa() { return _0x20b77a }, get 0xb() { return _0x446110 }, 0xc: Object, get 0xd() { return _0x483e03 }, get 0xe() { return _0x53f850 }, get 0xf() { return _0x2a900b }, get 0x10() { return _0x18b4be }, get 0x11() { return _0x462335 }, get 0x12() { return _0x4072ad }, get 0x13() { return _0x24dc34 }, get 0x14() { return navigator }, 0x15: arguments, 0x16: _0x38a8fe, 0x17: _0x406d4b, 0x18: _0x2e7a9b }, this ) } function _0x5e5a64(_0x27ec41, _0x4e1246) { var _0x15a192 = _0x5612de for (var _0x3f84da = {}, _0x389521 = -0x4bd * -0x1 + -0x28a + -0x233; _0x389521 < _0x4e1246['length']; _0x389521++) { var _0x58af98 = _0x4e1246[_0x389521], _0x1b7f4e = _0x27ec41[_0x58af98] null == _0x1b7f4e && (_0x1b7f4e = !(-0x1f76 + -0x1c06 + 0x3b7d * 0x1)), null === _0x1b7f4e || ('function' != typeof _0x1b7f4e && _0x15a192(0x17d) !== _0x1db123(_0x1b7f4e)) || (_0x1b7f4e = !(-0x2 * -0xef9 + -0xa1 * 0x3 + -0xb * 0x28d)), (_0x3f84da[_0x58af98] = _0x1b7f4e) } return _0x3f84da } function _0x2a6ac2() { var _0x42b9bc = _0x5612de return _0x5e5a64(navigator, [ _0x42b9bc(0x36b), 'appName', _0x42b9bc(0x17a), _0x42b9bc(0x246), _0x42b9bc(0x3a4), _0x42b9bc(0x360), _0x42b9bc(0x1fa), _0x42b9bc(0x33b), _0x42b9bc(0x38c), _0x42b9bc(0x212), 'vendorSub', 'doNotTrack', _0x42b9bc(0x24a), _0x42b9bc(0x2e2), _0x42b9bc(0x292), _0x42b9bc(0x390), _0x42b9bc(0x38f) ]) } function _0x226933() { var _0xe67fb0 = _0x5612de return _0x5e5a64(window, [ _0xe67fb0(0x29d), _0xe67fb0(0x222), _0xe67fb0(0x306), _0xe67fb0(0x26e), _0xe67fb0(0x366), 'isSecureContext', _0xe67fb0(0x3c0), _0xe67fb0(0x399), 'locationbar', _0xe67fb0(0x29f), _0xe67fb0(0x39f), _0xe67fb0(0x2e0), 'postMessage', 'webkitRequestAnimationFrame', _0xe67fb0(0x2de), 'netscape' ]) } function _0x1e5a7f() { var _0x577bf2 = _0x5612de return _0x5e5a64(document, [_0x577bf2(0x335), _0x577bf2(0x253), _0x577bf2(0x373), 'layers', _0x577bf2(0x2c0)]) } function _0x11a1d6() { var _0x3927af = _0x5612de, _0x306255 = document[_0x3927af(0x260)](_0x3927af(0x24d)), _0x3b8708 = null try { _0x3b8708 = _0x306255[_0x3927af(0x2f9)](_0x3927af(0x26b)) || _0x306255['getContext'](_0x3927af(0x3aa)) } catch (_0x30a5e5) { } return _0x3b8708 || (_0x3b8708 = null), _0x3b8708 } function _0x39c3d8(_0xc6dcf6) { var _0x59367a = _0x5612de, _0x5a3a25 = _0xc6dcf6[_0x59367a(0x1d7)](_0x59367a(0x1f1)) || _0xc6dcf6[_0x59367a(0x1d7)](_0x59367a(0x2e5)) || _0xc6dcf6[_0x59367a(0x1d7)](_0x59367a(0x31a)) if (_0x5a3a25) { var _0x5cca98 = _0xc6dcf6[_0x59367a(0x383)](_0x5a3a25[_0x59367a(0x1bf)]) return 0xb * -0x2b8 + 0xa * 0xe + 0x1d5c === _0x5cca98 && (_0x5cca98 = -0xe6 + -0x1909 + -0xe5 * -0x1d), _0x5cca98 } return null } function _0x425568() { var _0x556a1e = _0x5612de if (_0x6caf[_0x556a1e(0x23d)]) return _0x6caf[_0x556a1e(0x23d)] var _0x4f4b6e = _0x11a1d6() if (!_0x4f4b6e) return {} var _0x58c017 = { supportedExtensions: _0x4f4b6e[_0x556a1e(0x30f)]() || [], antialias: _0x4f4b6e[_0x556a1e(0x1c5)]()[_0x556a1e(0x1a5)], blueBits: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x27e)]), depthBits: _0x4f4b6e['getParameter'](_0x4f4b6e[_0x556a1e(0x252)]), greenBits: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x3c3)]), maxAnisotropy: _0x39c3d8(_0x4f4b6e), maxCombinedTextureImageUnits: _0x4f4b6e['getParameter'](_0x4f4b6e[_0x556a1e(0x1d2)]), maxCubeMapTextureSize: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x300)]), maxFragmentUniformVectors: _0x4f4b6e['getParameter'](_0x4f4b6e['MAX_FRAGMENT_UNIFORM_VECTORS']), maxRenderbufferSize: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x2da)]), maxTextureImageUnits: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x269)]), maxTextureSize: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x203)]), maxVaryingVectors: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x264)]), maxVertexAttribs: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e['MAX_VERTEX_ATTRIBS']), maxVertexTextureImageUnits: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x205)]), maxVertexUniformVectors: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e[_0x556a1e(0x19d)]), shadingLanguageVersion: _0x4f4b6e['getParameter'](_0x4f4b6e['SHADING_LANGUAGE_VERSION']), stencilBits: _0x4f4b6e['getParameter'](_0x4f4b6e['STENCIL_BITS']), version: _0x4f4b6e[_0x556a1e(0x383)](_0x4f4b6e['VERSION']) } return (_0x6caf[_0x556a1e(0x23d)] = _0x58c017), _0x58c017 } function _0x18707d() { var _0x52b59d = _0x5612de, _0x56cb86 = {} return ( (_0x56cb86[_0x52b59d(0x270)] = _0x2a6ac2()), (_0x56cb86[_0x52b59d(0x393)] = _0x226933()), (_0x56cb86[_0x52b59d(0x208)] = _0x1e5a7f()), (_0x56cb86[_0x52b59d(0x26b)] = _0x425568()), (_0x56cb86[_0x52b59d(0x381)] = _0x487576()), (_0x56cb86['plugins'] = _0x1f9824()), (_0x6caf['SECINFO'] = _0x56cb86), _0x56cb86 ) } function _0x572e48() { var _0x151b17 = _0x5612de return w_0x5c3140( _0x151b17(0x1d1), { get 0x0() { return _0x6caf }, get 0x1() { return _0x18707d }, 0x2: Date, get 0x3() { return _0x325f58 }, get 0x4() { return _0x328bde }, get 0x5() { return _0xdda738 }, 0x6: JSON, 0x7: arguments }, this ) } var _0x522d20 = { kCallTypeDirect: 0x0, kCallTypeInterceptor: 0x1 }, _0x2e10da = { kHttp: 0x0, kWebsocket: 0x1 }, _0x3f742e = _0x45b94b function _0x5646fa(_0x29e841) { var _0x2ecc2b = _0x5612de for ( var _0x5d379d, _0x5e2317, _0x34abf7 = [], _0x448a08 = -0x25ac + 0x1 * -0x1a4 + -0x128 * -0x22; _0x448a08 < _0x29e841[_0x2ecc2b(0x259)]; _0x448a08++ ) { ; (_0x5d379d = _0x29e841[_0x2ecc2b(0x195)](_0x448a08)), (_0x5e2317 = []) do { _0x5e2317[_0x2ecc2b(0x36e)]((-0x8d * -0x3e + 0x24d * -0x1 + -0x1eda) & _0x5d379d), (_0x5d379d >>= -0x6d * 0x11 + 0x75 * 0x11 + 0x10 * -0x8) } while (_0x5d379d) _0x34abf7 = _0x34abf7[_0x2ecc2b(0x2b8)](_0x5e2317['reverse']()) } return _0x34abf7 } function _0x6bc4ae(_0x4e8b7c) { } function _0x5b890d(_0x592717) { } function _0x16f345(_0x1a40af) { } function _0x361214(_0x426175) { } function _0xc35122(_0xe69c60, _0x3e14a1, _0x2d525a) { } var _0x5dde58 = { WEB_DEVICE_INFO: 0x8 } function _0x4df596(_0x14c951, _0x4c06b0) { var _0x3cd5a5 = _0x5612de return JSON[_0x3cd5a5(0x1e6)]({ magic: 0x20200422, version: 0x1, dataType: _0x14c951, strData: _0x4c06b0, tspFromClient: new Date()[_0x3cd5a5(0x16d)]() }) } function _0x29a5ac(_0x1a16de, _0x1af868, _0x2e45c3, _0x2a9bcc) { var _0x233cbb = _0x5612de return _0x32af0e(_0x233cbb(0x3a1), _0x1a16de, _0x1af868, _0x2e45c3, _0x2a9bcc) } function _0x32af0e(_0x58e2fa, _0x35c6ef, _0x5ce009, _0xba3041, _0x20e80f) { var _0x393ad1 = _0x5612de, _0x4841fc = new XMLHttpRequest() if ( (_0x4841fc[_0x393ad1(0x18b)](_0x58e2fa, _0x35c6ef, !(-0xb * 0x8b + -0x233 + 0x82c)), _0x20e80f && (_0x4841fc[_0x393ad1(0x1c6)] = !(0x1 * -0x260f + -0x2 * 0xcdf + 0x3fcd)), _0xba3041) ) for ( var _0x3f91e1 = -0x2ce + -0x1 * 0xe0f + 0x10dd, _0x2f8bec = Object['keys'](_0xba3041); _0x3f91e1 < _0x2f8bec[_0x393ad1(0x259)]; _0x3f91e1++ ) { var _0x475f86 = _0x2f8bec[_0x3f91e1], _0x42c2b4 = _0xba3041[_0x475f86] _0x4841fc[_0x393ad1(0x3ab)](_0x475f86, _0x42c2b4) } _0x4841fc[_0x393ad1(0x20a)](_0x5ce009) } function _0x2cd488(_0x751be6, _0x4c12d4) { var _0x253a32 = _0x5612de return ( _0x4c12d4 || (_0x4c12d4 = null), !!navigator['sendBeacon'] && (navigator[_0x253a32(0x24b)](_0x751be6, _0x4c12d4), !(-0x1da1 + 0x1e93 + -0xf2)) ) } function _0x4a2daf(_0x1ea426, _0x5a460b) { var _0x22c57e = _0x5612de try { window[_0x22c57e(0x1dc)] && window[_0x22c57e(0x1dc)][_0x22c57e(0x1c4)](_0x1ea426, _0x5a460b) } catch (_0xe6e06d) { } } function _0x34f60a(_0x1e7505) { var _0x389acb = _0x5612de try { window[_0x389acb(0x1dc)] && window[_0x389acb(0x1dc)][_0x389acb(0x2c3)](_0x1e7505) } catch (_0x5daf1b) { } } function _0x3d13cf(_0x3480fd) { var _0x1ccc66 = _0x5612de try { return window[_0x1ccc66(0x1dc)] ? window['localStorage']['getItem'](_0x3480fd) : null } catch (_0x3bb8f0) { return null } } function _0x21db29(_0x584f42, _0xde0f43) { var _0x4464a1 = _0x5612de for ( var _0x2b8d40, _0x22bd9c = [], _0x13f024 = 0x1856 * 0x1 + -0x6a * 0x20 + -0x16 * 0x81, _0x5648fb = '', _0x4c41a3 = -0x2 * -0xc67 + -0xf91 + -0x5 * 0x1d9; _0x4c41a3 < -0x1 * -0x322 + -0x25ce + 0x23ac; _0x4c41a3++ ) _0x22bd9c[_0x4c41a3] = _0x4c41a3 for (var _0x4d4c13 = -0x18e4 + -0x3 * -0x10f + 0x15b7; _0x4d4c13 < -0x36a * -0x8 + 0x1cf7 + 0x126d * -0x3; _0x4d4c13++) (_0x13f024 = (_0x13f024 + _0x22bd9c[_0x4d4c13] + _0x584f42[_0x4464a1(0x195)](_0x4d4c13 % _0x584f42[_0x4464a1(0x259)])) % (-0x577 * 0x3 + 0x4eb + 0xc7a)), (_0x2b8d40 = _0x22bd9c[_0x4d4c13]), (_0x22bd9c[_0x4d4c13] = _0x22bd9c[_0x13f024]), (_0x22bd9c[_0x13f024] = _0x2b8d40) var _0x11b95d = -0x7d8 + -0x256 + -0x517 * -0x2 _0x13f024 = -0x1bef + -0xbc5 * -0x3 + -0x760 * 0x1 for (var _0x15a79f = 0xd * 0x12e + 0x80 * -0x3d + 0xf2a; _0x15a79f < _0xde0f43[_0x4464a1(0x259)]; _0x15a79f++) (_0x13f024 = (_0x13f024 + _0x22bd9c[(_0x11b95d = (_0x11b95d + (0x8ed + -0x1 * -0x836 + -0x22 * 0x81)) % (0x32b * 0x7 + 0x2311 + -0x2 * 0x1c1f))]) % (-0x1 * -0x106d + 0x35e * 0x5 + -0x2043)), (_0x2b8d40 = _0x22bd9c[_0x11b95d]), (_0x22bd9c[_0x11b95d] = _0x22bd9c[_0x13f024]), (_0x22bd9c[_0x13f024] = _0x2b8d40), (_0x5648fb += String[_0x4464a1(0x1e2)]( _0xde0f43[_0x4464a1(0x195)](_0x15a79f) ^ _0x22bd9c[(_0x22bd9c[_0x11b95d] + _0x22bd9c[_0x13f024]) % (0x179 * -0x7 + 0x2385 + -0x2 * 0xc1b)] )) return _0x5648fb } var _0x45bf15 = _0x21db29, _0x48a082 = {} function _0x641e3d(_0x21dbac, _0x4a67ec) { var _0x51016d = _0x5612de return w_0x5c3140( _0x51016d(0x3c4), { 0x0: String, 0x1: Math, get 0x2() { return _0x45bf15 }, get 0x3() { return _0x389396 }, 0x4: arguments, 0x5: _0x21dbac, 0x6: _0x4a67ec }, this ) } ; (_0x48a082['pb'] = -0xd0f * -0x1 + 0xade * 0x2 + -0x22c9), (_0x48a082['json'] = 0x405 + -0x1 * -0xe59 + -0x125d) var _0x216650 = { kNoMove: 0x2, kNoClickTouch: 0x4, kNoKeyboardEvent: 0x8, kMoveFast: 0x10, kKeyboardFast: 0x20, kFakeOperations: 0x40 }, _0x5dc9cc = { sTm: 0x0, acc: 0x0 } function _0x18a9f7() { var _0x4e02b7 = _0x5612de try { var _0x41737c = _0x3d13cf(_0x4e02b7(0x343)) _0x41737c ? Object[_0x4e02b7(0x2a0)](_0x5dc9cc, JSON[_0x4e02b7(0x3b1)](_0x41737c)) : ((_0x5dc9cc[_0x4e02b7(0x293)] = new Date()[_0x4e02b7(0x16d)]()), (_0x5dc9cc[_0x4e02b7(0x27d)] = -0x175c + -0x1066 + 0x27c2)) } catch (_0x3da833) { ; (_0x5dc9cc[_0x4e02b7(0x293)] = new Date()[_0x4e02b7(0x16d)]()), (_0x5dc9cc[_0x4e02b7(0x27d)] = -0x1 * -0x1129 + -0x1f1f + -0x1 * -0xdf6), _0x26e186() } } function _0x26e186() { var _0x48e1a8 = _0x5612de _0x4a2daf(_0x48e1a8(0x343), JSON['stringify'](_0x5dc9cc)) } var _0xf63a81 = { T_MOVE: 0x1, T_CLICK: 0x2, T_KEYBOARD: 0x3 }, _0x2786f5 = !(0x1f31 * -0x1 + 0x1 * 0x22c7 + 0x83 * -0x7), _0x9fb121 = [], _0x207cc5 = [], _0x191fa5 = [], _0xe06992 = { ubcode: 0x0 }, _0x388856 = function (_0x4e0342, _0x5ca571) { return _0x4e0342 + _0x5ca571 }, _0x20a3d9 = function (_0x2309ca) { return _0x2309ca * _0x2309ca } function _0x9c0be2(_0x232ed8, _0x432cf8) { var _0x59688f = _0x5612de if ( (_0x232ed8[_0x59688f(0x259)] > 0x1 * 0xa93 + 0x1d7a + -0xd17 * 0x3 && _0x232ed8['splice'](0x1ab7 + 0x1 * -0x2147 + -0x1a4 * -0x4, 0x617 + 0x280 + 0x1 * -0x833), _0x232ed8[_0x59688f(0x259)] > -0x1c57 + 0x1059 + 0xbfe) ) { var _0x97b7e7 = _0x232ed8[_0x232ed8['length'] - (-0xc0e + 0xb26 * 0x2 + 0xa3d * -0x1)] if ( _0x432cf8['d'] - _0x97b7e7['d'] <= 0x5 * -0x1a3 + -0x91 * -0x32 + 0x5 * -0x407 || ('y' in _0x432cf8 && _0x432cf8['x'] === _0x97b7e7['x'] && _0x432cf8['y'] === _0x97b7e7['y']) ) return } _0x232ed8[_0x59688f(0x36e)](_0x432cf8) } function _0x1d26db(_0x261f4b, _0x3c3c83, _0x131716) { var _0x10f2ca = _0x5612de if (_0x462335['enableTrack']) { if (_0x131716 !== _0xf63a81['T_MOVE']) return _0x131716 === _0xf63a81[_0x10f2ca(0x1f0)] ? (_0x261f4b[_0x10f2ca(0x259)] >= 0x1167 + -0x856 * -0x4 + 0x1 * -0x30cb && _0x450b73(), void _0x261f4b[_0x10f2ca(0x36e)](_0x3c3c83)) : _0x131716 === _0xf63a81[_0x10f2ca(0x355)] ? (_0x261f4b[_0x10f2ca(0x259)] > -0x1b6 * 0x16 + -0x115 * 0x17 + 0x11 * 0x3cb && _0x450b73(), void _0x261f4b['push'](_0x3c3c83)) : void (-0x15a4 + -0xc9f + 0x2243) if ( (_0x261f4b['length'] >= -0x5b9 + -0x1b5 + -0x2 * -0x4b1 && _0x450b73(), _0x261f4b[_0x10f2ca(0x259)] > 0x13e * 0x6 + 0x4a5 * -0x2 + 0x1d6) ) { var _0x40dc65 = _0x261f4b[_0x261f4b[_0x10f2ca(0x259)] - (-0x233e + 0x6bf + 0x1c80)], _0x243563 = _0x40dc65['x'], _0x7ef629 = _0x40dc65['y'], _0x293666 = _0x40dc65['ts'] if (_0x243563 === _0x3c3c83['x'] && _0x7ef629 === _0x3c3c83['y']) return if (_0x3c3c83['ts'] - _0x293666 < -0x1 * -0x9dc + -0x7 * -0x32d + -0x1e23) return } _0x261f4b['push'](_0x3c3c83) } } var _0x19ffaf = { init: 0x0, running: 0x1, exit: 0x2, flush: 0x3 } function _0x450b73(_0xd6648d) { var _0x5b1d4d = _0x5612de return w_0x5c3140( _0x5b1d4d(0x3a2), { get 0x0() { return _0x6caf }, get 0x1() { return _0x19ffaf }, 0x2: Date, get 0x3() { return _0x5dc9cc }, get 0x4() { return _0x462335 }, get 0x5() { return _0x26e186 }, 0x6: Object, get 0x7() { return _0x4df596 }, get 0x8() { return _0x5dde58 }, get 0x9() { return _0x641e3d }, 0xa: JSON, get 0xb() { return _0x48a082 }, get 0xc() { return _0x2cd488 }, get 0xd() { return _0x29a5ac }, 0xe: arguments, 0xf: _0xd6648d }, this ) } function _0x58c311() { var _0x30dab3 = _0x5612de _0x462335[_0x30dab3(0x37f)] && _0x450b73(_0x19ffaf['exit']) } var _0x1a755e = {} ; (_0x1a755e[_0x5612de(0x2d4)] = _0x3dcfd5), (_0x1a755e['touchmove'] = _0x3dcfd5), (_0x1a755e[_0x5612de(0x364)] = _0x56114b), (_0x1a755e[_0x5612de(0x1d6)] = _0x19d89b), (_0x1a755e[_0x5612de(0x2d3)] = _0x19d89b) var _0x18582a = !(0x1796 + -0xf7d + -0x818) function _0x1dbe74() { var _0x101f5b = _0x5612de if (document && document[_0x101f5b(0x2f6)] && !_0x18582a) { for ( var _0x1dfebe = 0x1 * -0xe36 + 0x6e8 + -0xa * -0xbb, _0x5af0b0 = Object[_0x101f5b(0x17f)](_0x1a755e); _0x1dfebe < _0x5af0b0[_0x101f5b(0x259)]; _0x1dfebe++ ) { var _0x2ecc3c = _0x5af0b0[_0x1dfebe] document[_0x101f5b(0x2f6)](_0x2ecc3c, _0x1a755e[_0x2ecc3c]) } _0x18582a = !(-0x1 * -0xfcb + 0x21 * 0x65 + -0x1cd0) } } function _0x3dcfd5(_0x1f9f7e) { var _0x4f99fd = _0x5612de, _0x395631 = _0x1f9f7e, _0x1f0c31 = _0x1f9f7e['type'] _0x1f9f7e[_0x4f99fd(0x379)] && _0x4f99fd(0x299) === _0x1f0c31 && ((_0x395631 = _0x1f9f7e['touches'][-0x9 * -0x3f4 + 0x1 * 0xc73 + -0x3007]), (_0x2786f5 = !(-0x129a + 0x1bca + -0x930))) var _0x5d0e65 = { x: Math[_0x4f99fd(0x1cf)](_0x395631['clientX']), y: Math[_0x4f99fd(0x1cf)](_0x395631['clientY']), d: Date[_0x4f99fd(0x34d)]() } _0x9c0be2(_0x9fb121, _0x5d0e65), _0x1d26db( _0x6caf[_0x4f99fd(0x21d)], { ts: _0x5d0e65['d'], x: _0x5d0e65['x'], y: _0x5d0e65['y'] }, _0xf63a81[_0x4f99fd(0x2be)] ) } function _0x56114b(_0x35e1c1) { var _0x3de3de = _0x5612de, _0x411a0a = 0x22e7 + -0x5 * -0x133 + -0x28e6 ; (_0x35e1c1[_0x3de3de(0x28c)] || _0x35e1c1['ctrlKey'] || _0x35e1c1['metaKey'] || _0x35e1c1[_0x3de3de(0x22e)]) && (_0x411a0a = 0xe7c + -0x3 * 0x143 + -0xab2) var _0x5239f5 = { x: _0x411a0a, d: Date['now']() } _0x9c0be2(_0x191fa5, _0x5239f5), _0x1d26db( _0x6caf[_0x3de3de(0x391)], { ts: _0x5239f5['d'] }, _0xf63a81[_0x3de3de(0x355)] ) } function _0x19d89b(_0x39a86c) { var _0x3bb659 = _0x5612de, _0x4a9de2 = _0x39a86c, _0x33eb04 = _0x39a86c['type'] _0x39a86c[_0x3bb659(0x379)] && 'touchstart' === _0x33eb04 && ((_0x4a9de2 = _0x39a86c['touches'][0x1491 + 0x1 * -0x1216 + -0x1 * 0x27b]), (_0x2786f5 = !(-0x1 * -0x853 + 0x12df * 0x2 + -0x2e11))) var _0xf57aea = { x: Math['floor'](_0x4a9de2[_0x3bb659(0x2bf)]), y: Math[_0x3bb659(0x1cf)](_0x4a9de2['clientY']), d: Date['now']() } _0x9c0be2(_0x207cc5, _0xf57aea), _0x1d26db( _0x6caf[_0x3bb659(0x3b6)], { ts: _0xf57aea['d'], x: _0xf57aea['x'], y: _0xf57aea['y'] }, _0xf63a81[_0x3bb659(0x1f0)] ) } function _0x42fe9b(_0x320405) { var _0x2bf333 = _0x5612de return _0x320405['reduce'](_0x388856) / _0x320405[_0x2bf333(0x259)] } function _0x3ea7d6(_0xbdd4a6) { var _0x1e5c1e = _0x5612de if (_0xbdd4a6[_0x1e5c1e(0x259)] <= -0x1 * -0x2420 + 0xc87 * -0x1 + 0x5e6 * -0x4) return -0x1 * -0x309 + 0x15 * 0x9d + -0xfea * 0x1 var _0x3deca4 = _0x42fe9b(_0xbdd4a6), _0x58472b = _0xbdd4a6['map'](function (_0x508d28) { return _0x508d28 - _0x3deca4 }) return Math[_0x1e5c1e(0x317)]( _0x58472b['map'](_0x20a3d9)[_0x1e5c1e(0x376)](_0x388856) / (_0xbdd4a6[_0x1e5c1e(0x259)] - (0xa * 0x127 + -0x2103 + -0xe * -0x189)) ) } function _0x52f064(_0x2031c9, _0x5a5379, _0xb6ab78) { var _0x1d0db5 = _0x5612de, _0xcfe257 = 0xae8 + -0xb * -0x6f + -0xfad, _0x4f9c60 = -0x894 + -0x12a7 + 0x1 * 0x1b3b if (_0x2031c9[_0x1d0db5(0x259)] > _0x5a5379) { for ( var _0x147b41 = [], _0x5ca0e0 = -0x10a8 + -0x212f + 0x3 * 0x109d; _0x5ca0e0 < _0x2031c9[_0x1d0db5(0x259)] - (0x557 * -0x7 + -0x5 * -0xc6 + 0x14a * 0x1a); _0x5ca0e0++ ) { var _0x2a170e = _0x2031c9[_0x5ca0e0 + (-0x20c6 * -0x1 + 0x1f31 + -0x3ff6)], _0x1f8ecf = _0x2031c9[_0x5ca0e0], _0x1b82ec = _0x2a170e['d'] - _0x1f8ecf['d'] _0x1b82ec && (_0xb6ab78 ? _0x147b41[_0x1d0db5(0x36e)]((0xf98 + 0x90f + 0x2 * -0xc53) / _0x1b82ec) : _0x147b41[_0x1d0db5(0x36e)]( Math[_0x1d0db5(0x317)](_0x20a3d9(_0x2a170e['x'] - _0x1f8ecf['x']) + _0x20a3d9(_0x2a170e['y'] - _0x1f8ecf['y'])) / _0x1b82ec )) } ; (_0xcfe257 = _0x42fe9b(_0x147b41)), 0x5 * -0x79d + 0xf2d * -0x1 + -0xeb * -0x3a === (_0x4f9c60 = _0x3ea7d6(_0x147b41)) && (_0x4f9c60 = 0xcc5 + -0x1 * -0x9e1 + -0x16a6 + 0.01) } return [_0xcfe257, _0x4f9c60] } function _0x26d461() { var _0x3f77b6 = _0x5612de, _0x5e9ee6 = !(0x9d * -0x6 + 0x16b0 + -0x1301), _0x499168 = -0x21e + -0x1b6a + 0x28 * 0xbd try { document && document['createEvent'] && (document[_0x3f77b6(0x188)](_0x3f77b6(0x240)), (_0x5e9ee6 = !(0x195e + -0x5 * -0x371 + -0x3f * 0xad))) } catch (_0x4b2baa) { } var _0x462d0a = _0x52f064(_0x9fb121, 0x6a * 0x2 + -0x1b * 0x16b + 0x2576), _0x136148 = _0x52f064(_0x191fa5, -0x94c + -0xd * 0x51 + 0xd6e, !(0x1 * 0x7ed + -0xab4 + 0x2c7)), _0x17d8e6 = -0x2 * 0xb95 + -0xda0 + 0x24cb !_0x5e9ee6 && _0x2786f5 && ((_0x17d8e6 |= 0x2468 + -0x1 * 0x2c2 + -0x2166), (_0x499168 |= _0x216650[_0x3f77b6(0x2f2)])), -0x293 * -0x3 + 0x1 * 0xdad + -0x1566 === _0x9fb121['length'] ? ((_0x17d8e6 |= -0x1cf3 * 0x1 + 0x12e1 + 0xa14), (_0x499168 |= _0x216650[_0x3f77b6(0x2fe)])) : _0x462d0a[-0x17f8 + -0x1eae + 0x36a6] > 0xbab + -0x1fb9 + 0x3 * 0x6c0 && ((_0x17d8e6 |= 0x20 * -0x5c + 0xb22 + 0x6e), (_0x499168 |= _0x216650['kMoveFast'])), 0x2297 * -0x1 + 0x57b * 0x3 + 0x65 * 0x2e === _0x207cc5['length'] && ((_0x17d8e6 |= 0x15a5 + 0x557 + -0x1af8), (_0x499168 |= _0x216650['kNoClickTouch'])), 0x20bb + 0x1e5f + 0x1f8d * -0x2 === _0x191fa5[_0x3f77b6(0x259)] ? ((_0x17d8e6 |= -0x1 * 0x1b73 + -0x43e + 0x1fb9), (_0x499168 |= _0x216650['kNoKeyboardEvent'])) : _0x136148[0x16ee + -0x1 * 0x1e99 + 0x7ab] > 0x1 * 0xb77 + -0x82 + -0xaf5 + 0.5 && ((_0x17d8e6 |= 0x176a + 0x183 + 0x7 * -0x38b), (_0x499168 |= _0x216650[_0x3f77b6(0x3bf)])), (_0xe06992['ubcode'] = _0x499168) var _0x9340b9 = _0x17d8e6[_0x3f77b6(0x3ae)](-0x2018 + -0x543 * 0x7 + 0x450d) return ( 0xc8e * 0x1 + -0x3 * 0x3ca + -0x12f === _0x9340b9['length'] ? (_0x9340b9 = '00' + _0x9340b9) : -0x117a + 0x19 * -0x57 + 0x8a9 * 0x3 === _0x9340b9[_0x3f77b6(0x259)] && (_0x9340b9 = '0' + _0x9340b9), _0x9340b9 ) } function _0x5047d8() { _0x450b73(-0x1b05 + 0x103 * 0x1c + -0x4 * 0x53) } function _0x4145f8(_0x30c511, _0x35c283) { var _0x46d631 = _0x5612de for ( var _0x3d95be = _0x35c283[_0x46d631(0x259)], _0x3c9714 = new ArrayBuffer(_0x3d95be + (-0x2ef * -0x2 + 0x1bbd + 0x2e * -0xbb)), _0x1054b9 = new Uint8Array(_0x3c9714), _0x5633c2 = -0x114 + -0x2096 + 0x21aa, _0x28d040 = 0x10a * -0x1a + 0x5 * 0x5cf + -0x207 * 0x1; _0x28d040 < _0x3d95be; _0x28d040++ ) (_0x1054b9[_0x28d040] = _0x35c283[_0x28d040]), (_0x5633c2 ^= _0x35c283[_0x28d040]) _0x1054b9[_0x3d95be] = _0x5633c2 var _0x280d0b = (-0xe * -0x98 + 0x1f * 0x9e + 0x6f * -0x3d) & Math[_0x46d631(0x1cf)]((-0x1 * 0x13ed + -0x2 * 0x581 + 0x1fee) * Math[_0x46d631(0x18e)]()), _0x418204 = String[_0x46d631(0x1e2)][_0x46d631(0x207)](null, _0x1054b9), _0x250194 = _0x21db29(String[_0x46d631(0x1e2)](_0x280d0b), _0x418204), _0x37237c = '' return ( (_0x37237c += String[_0x46d631(0x1e2)](_0x30c511)), (_0x37237c += String[_0x46d631(0x1e2)](_0x280d0b)), _0x389396((_0x37237c += _0x250194), 's1') ) } function _0x1633f2(_0x48f290, _0x504655, _0x4fa808, _0x1a5c57, _0x3a4737) { var _0x5a9e67 = _0x5612de _0x5863d1(), _0x26d461(), void (0x247a + -0x3f2 + -0x2088) !== _0x1a5c57 && '' !== _0x1a5c57 && (_0x1a5c57 = '') var _0x21ca02 = _0x5dd467(_0x1a5c57) _0x3a4737 || (_0x3a4737 = '00000000000000000000000000000000') var _0x1fb174 = new ArrayBuffer(0x1cc4 + -0x1109 + -0x3e6 * 0x3), _0x1ffaa7 = new Uint8Array(_0x1fb174), _0xeefda2 = (0x22cb + 0x1 * -0x32c + 0x1f9f * -0x1) | (_0x48f290 << (-0x228e + 0x22f4 * 0x1 + -0x60)) | (_0x504655 << (0x1075 + -0x2c * -0x26 + -0x16f8)) | (((-0x261a + 0x1e95 + 0x786) & Math[_0x5a9e67(0x1cf)]((0x705 + 0x1069 + -0x3 * 0x7ae) * Math[_0x5a9e67(0x18e)]())) << (0x3f4 * 0x5 + 0x59a + -0x195a)) | (-0x1 * -0x2033 + 0x284 * 0x5 + 0xeed * -0x3) _0x6caf[_0x5a9e67(0x326)]++ _0x6caf['envcode'] = 1 var _0x5eb39b = (-0x55 + 0x8a3 + -0x80f) & _0x6caf[_0x5a9e67(0x326)] ; (_0x1ffaa7[0x18e0 * 0x1 + 0xd8d + -0x266d] = (_0x4fa808 << (-0x1 * 0x1117 + -0x144f + 0x256c)) | _0x5eb39b), (_0x1ffaa7[-0x177d + 0x3 * 0xb39 + -0xa2d] = (_0x6caf['envcode'] >> (-0x163b + 0x2c3 + 0x1380)) & (0x15b3 + -0x1efd + 0xa49 * 0x1)), (_0x1ffaa7[-0x5e3 + -0x1 * 0x1535 + 0x1b1a * 0x1] = (0x64a + -0xc * 0xa3 + 0x259) & _0x6caf[_0x5a9e67(0x380)]), (_0x1ffaa7[0x81 * 0x11 + 0xa49 * 0x1 + -0x12d7] = _0xe06992[_0x5a9e67(0x382)]) var _0x13f487 = _0x42e709[_0x5a9e67(0x2b7)](_0x5dd467(_0x42e709[_0x5a9e67(0x2b7)](_0x21ca02))) ; (_0x1ffaa7[-0xf6b * 0x2 + 0x1c4 + 0x1d16] = _0x13f487[-0x81a + -0x24ee + -0x18e * -0x1d]), (_0x1ffaa7[0x73d * -0x3 + 0x2335 + -0x1 * 0xd79] = _0x13f487[-0x16 * -0x4 + -0xfdd + 0x3e5 * 0x4]) var _0x136ce1 = _0x42e709['decode'](_0x5dd467(_0x42e709['decode'](_0x3a4737))) return ( (_0x1ffaa7[0x17 * -0x35 + 0x220e + -0x1d45] = _0x136ce1[0xe7 * -0x11 + 0x1 * -0x17a1 + 0x2706]), (_0x1ffaa7[0x1b8 + -0x2 * -0x665 + 0x151 * -0xb] = _0x136ce1[-0x276 * 0x9 + -0x1335 + -0x39 * -0xba]), (_0x1ffaa7[0x1fa8 + 0x776 + 0x1 * -0x2716] = (-0x23cd + -0x69d + 0x2b69) & Math[_0x5a9e67(0x1cf)]((0x9c + 0x77b * 0x4 + -0x1 * 0x1d89) * Math[_0x5a9e67(0x18e)]())), _0x4145f8(_0xeefda2, _0x1ffaa7) ) } function _0x34c70a(_0xf6b3d0, _0x289075, _0x2c48ed) { var _0x1fe583 = _0x5612de return { 'X-Bogus': _0x1633f2(_0x2e10da[_0x1fe583(0x289)], _0x462335['initialized'], _0xf6b3d0, null, _0x2c48ed) } } function _0x11233a(_0x34d47b, _0x1b3ba5, _0x55dcd4) { var _0x3e598d = _0x5612de return { 'X-Bogus': _0x1633f2(_0x2e10da[_0x3e598d(0x1df)], _0x462335[_0x3e598d(0x1fc)], _0x34d47b, _0x1b3ba5, _0x55dcd4) } } function _0x5c2014(_0x1fa689) { return w_0x5c3140( '484e4f4a403f524300362d0a5f00233c0000000029b6a730000000630214000103001400020700001400030700011400041101031100031347000d11010311000313140001450023110103110004134700130211010011010311000413430114000145000607000214000102110101110002021100014303140005110005420003096b1e7e601e606766710c6b1e7e601e63726a7f7c7277200303030303030303030303030303030303030303030303030303030303030303', { get 0x0() { return _0x5dd467 }, get 0x1() { return _0x34c70a }, 0x2: arguments, 0x3: _0x1fa689 }, this ) } function _0x3c875d(_0x17e2b2, _0x1e7967) { var _0x36f0c4 = _0x5612de, _0x292251 = new Uint8Array(-0x1d76 + 0xa81 * -0x3 + 0x3cfc) return ( (_0x292251[0xff * 0x25 + 0x1ee0 * -0x1 + -0x5fb] = _0x17e2b2 / (0x1126 * -0x2 + -0x1 * 0x20f6 + -0x2 * -0x2221)), (_0x292251[0x29 * -0xde + 0x25a6 + 0x6b * -0x5] = _0x17e2b2 % (-0x5 * 0x705 + 0x10bd + -0xb1 * -0x1c)), (_0x292251[-0x1 * -0x1fb5 + -0x1921 + -0x692] = _0x1e7967 % (0x1615 + -0xda0 + 0x1 * -0x775)), String[_0x36f0c4(0x1e2)][_0x36f0c4(0x207)](null, _0x292251) ) } function _0x4b49f3(_0xe64465) { var _0x2fa114 = _0x5612de return String[_0x2fa114(0x1e2)](_0xe64465) } function _0x26151b(_0x51896f, _0x3a647f, _0x2db6f6) { return _0x4b49f3(_0x51896f) + _0x4b49f3(_0x3a647f) + _0x2db6f6 } function _0xc38697(_0x5bf566, _0x20667e) { return _0x389396(_0x5bf566, _0x20667e) } function _0x538c80( _0x213380, _0x5bb06d, _0x2807a8, _0x2bbe8d, _0x43c759, _0x510d57, _0x5b433d, _0x30b81d, _0x392407, _0x124f15, _0x22fc4c, _0x56f654, _0x8ab411, _0x1c9de4, _0x24f978, _0x27f46c, _0x1bd4f9, _0x572854, _0x34f6a0 ) { var _0x2e1799 = _0x5612de, _0x432584 = new Uint8Array(0x22bb + 0xd * -0x2bd + 0x1 * 0xf1) return ( (_0x432584[-0xc70 + 0x5e9 + 0x22d * 0x3] = _0x213380), (_0x432584[-0x2 * -0x127c + -0x1 * 0x1f61 + -0x596] = _0x22fc4c), (_0x432584[-0x1af * 0xb + 0x97b + 0xc1 * 0xc] = _0x5bb06d), (_0x432584[-0xfc5 * -0x2 + -0x5e5 + -0x19a2] = _0x56f654), (_0x432584[-0x35 * 0xa3 + -0x10c9 * -0x2 + 0x1 * 0x31] = _0x2807a8), (_0x432584[0x1d1d + 0x124a + -0x1 * 0x2f62] = _0x8ab411), (_0x432584[-0x1 * -0xb49 + -0x5d1 + -0x572] = _0x2bbe8d), (_0x432584[-0x18e * -0xe + 0xff * 0x22 + -0x379b] = _0x1c9de4), (_0x432584[-0x697 * 0x2 + 0xcc8 + 0x5 * 0x16] = _0x43c759), (_0x432584[0x2 * 0x8bf + 0xcc4 + -0x1e39] = _0x24f978), (_0x432584[0x63 * -0x43 + -0x242 + 0x3 * 0x967] = _0x510d57), (_0x432584[0x1aa9 + 0xe38 + 0x1 * -0x28d6] = _0x27f46c), (_0x432584[-0xdee + -0x1 * 0x105b + 0x1e55 * 0x1] = _0x5b433d), (_0x432584[0x1 * -0x1543 + -0x1 * 0x1b5b + 0x1 * 0x30ab] = _0x1bd4f9), (_0x432584[0xc86 * -0x1 + 0x1c9 + 0xacb] = _0x30b81d), (_0x432584[0x1581 + -0x70c + -0xe66] = _0x572854), (_0x432584[0x1dc1 + 0xd * 0xb5 + -0x26e2] = _0x392407), (_0x432584[-0x36 * 0x4a + 0x268a + -0x16dd] = _0x34f6a0), (_0x432584[0xf * -0x1ca + -0x16c2 + 0x31aa] = _0x124f15), String['fromCharCode'][_0x2e1799(0x207)](null, _0x432584) ) } var _0x3c4305 = !(-0xc6b + 0x270e * 0x1 + -0x1aa2) function _0x8edc3d(_0x22218f, _0x1e70b9) { var _0x364732 = _0x5612de return w_0x5c3140( _0x364732(0x2b2), { get 0x0() { return _0x5dd467 }, get 0x1() { return _0x3c4305 }, set 0x1(_0x539e8c) { _0x3c4305 = _0x539e8c }, get 0x2() { return _0x462335 }, get 0x3() { return _0x5863d1 }, get 0x4() { return _0x26d461 }, get 0x5() { return _0xe06992 }, get 0x6() { return _0x6caf }, get 0x7() { return _0x42e709 }, 0x8: String, get 0x9() { return navigator }, get 0xa() { return _0x3c875d }, get 0xb() { return _0x21db29 }, get 0xc() { return _0xc38697 }, 0xd: Date, get 0xe() { return _0x18b4be }, get 0xf() { return _0x538c80 }, get 0x10() { return _0x4b49f3 }, get 0x11() { return _0x26151b }, get 0x12() { return _0x389396 }, 0x13: arguments, 0x14: _0x22218f, 0x15: _0x1e70b9, 0x16: RegExp }, this ) } function _0x556182(_0x5e8c32) { var _0x4a1328 = _0x5612de _0x4a2daf(_0x4a1328(0x28a), _0x5e8c32) } function _0x5141ac() { var _0x2770a6 = _0x3d13cf('xmst') return _0x2770a6 || '' } function _0x50686a(_0x193aca) { var _0x460363 = _0x5612de return _0x460363(0x331) === Object[_0x460363(0x344)][_0x460363(0x3ae)][_0x460363(0x334)](_0x193aca) } function _0x2195cd(_0x383b5f, _0x4a7858) { var _0x20b490 = _0x5612de if (_0x383b5f) { var _0x11f5aa = _0x383b5f[_0x4a7858] if (_0x11f5aa) { var _0x4fcde1 = _0x1db123(_0x11f5aa) return _0x20b490(0x17d) === _0x4fcde1 || _0x20b490(0x1ee) === _0x4fcde1 ? -0x1 * -0x4e8 + 0x18eb + -0x1dd2 : 'string' === _0x4fcde1 ? _0x4fcde1[_0x20b490(0x259)] > -0x124c + 0x20c3 + -0xe77 ? 0x35 * 0x34 + 0x1ec8 + -0x298b : -0x8a * 0x31 + -0x18c7 + -0x1111 * -0x3 : _0x50686a(_0x11f5aa) ? -0x1 * -0xc83 + -0x3 * 0x466 + 0x4 * 0x2c : 0x1018 + -0x371 * -0x9 + 0x1 * -0x2f0f } } return -0x155a + 0x4c * -0x6c + 0x4 * 0xd5b } function _0xdc4d4c(_0x3c0aaa) { var _0x11952c = _0x5612de try { var _0x57243b = Object[_0x11952c(0x344)][_0x11952c(0x3ae)][_0x11952c(0x334)](_0x3c0aaa) return _0x11952c(0x30e) === _0x57243b ? !(-0x1 * 0x7c5 + 0x1 * -0x853 + 0x338 * 0x5) === _0x3c0aaa ? -0xa1 * -0x23 + 0x2 * 0xaa9 + -0x2b54 : -0x1e71 * 0x1 + 0x1 * 0x1885 + 0x5ee : _0x11952c(0x1af) === _0x57243b ? -0xce * 0x25 + 0x1e1a + 0x3 * -0x1b : '[object\x20Undefined]' === _0x57243b ? -0x1 * 0x159a + -0x684 + 0x1c22 : _0x11952c(0x1ce) === _0x57243b ? -0x3a * -0x70 + 0x4b1 + 0xa04 * -0x3 : '[object\x20String]' === _0x57243b ? '' === _0x3c0aaa ? 0x12 * 0xad + 0x3b * 0x71 + -0x262e : 0x3 * 0xf8 + 0x22ec + -0x25cc : _0x11952c(0x331) === _0x57243b ? -0x1 * -0x874 + -0x1 * 0x2197 + 0x1923 === _0x3c0aaa['length'] ? -0xf6f + -0x1ee3 + 0x2e5b : -0x10c3 + -0x466 * -0x4 + 0x7 * -0x1d : _0x11952c(0x37b) === _0x57243b ? 0x1 * 0x22e6 + 0x1 * 0x2669 + 0x824 * -0x9 : _0x11952c(0x1fe) === _0x57243b ? 0x2392 + -0x15db + -0xdab : _0x11952c(0x17d) === _0x1db123(_0x3c0aaa) ? -0x3 * 0xd7 + -0x17b0 + 0x1a98 : -(-0x8e4 + 0x2 * 0xd1b + -0x1151) } catch (_0x320465) { return -(-0x62e * 0x1 + 0x3 * -0x3ec + 0x11f4) } } var _0x2d8bb4 = {} function _0x241339() { var _0x5d55e6 = _0x5612de return document[_0x5d55e6(0x373)] ? 'IE' : -0xc04 + -0xbe8 + 0x17ec } function _0x5011f8() { var _0x52b3d6 = _0x5612de return eval['toString']()[_0x52b3d6(0x259)] } function _0x58210c(_0x4d43be, _0x3faa08, _0x3d51f5) { var _0x16b761 = _0x5612de for (var _0x4738ee = {}, _0x793fa7 = 0x111 + -0x209 * 0x1 + 0x1f * 0x8; _0x793fa7 < _0x3faa08[_0x16b761(0x259)]; _0x793fa7++) { var _0x15231e = void (-0xf02 * -0x1 + 0xe35 + -0x1d37), _0x2d01fa = void (-0x782 + 0x5 * -0x143 + 0xdd1), _0x17bcc5 = _0x3faa08[_0x793fa7] try { _0x4d43be && (_0x15231e = _0x4d43be[_0x17bcc5]) } catch (_0x1de94f) { } if ('string' === _0x3d51f5) _0x2d01fa = '' + _0x15231e else { if (_0x16b761(0x28b) === _0x3d51f5) _0x2d01fa = _0x15231e ? Math[_0x16b761(0x1cf)](_0x15231e) : -(-0x19f0 + 0x1ada + 0xe9 * -0x1) else { if (_0x16b761(0x1ab) !== _0x3d51f5) throw Error(_0x16b761(0x256)) _0x2d01fa = _0xdc4d4c(_0x15231e) } } _0x4738ee[_0x17bcc5] = _0x2d01fa } return _0x4738ee } function _0x3a2b92() { var _0x53dacb = _0x5612de, _0x1c216f Object[_0x53dacb(0x2a0)]( _0x2d8bb4[_0x53dacb(0x270)], _0x58210c( navigator, [ _0x53dacb(0x36b), _0x53dacb(0x350), _0x53dacb(0x184), 'appVersion', _0x53dacb(0x32d), 'doNotTrack', _0x53dacb(0x39a), _0x53dacb(0x38c), _0x53dacb(0x17a), _0x53dacb(0x246), 'productSub', 'cpuClass', _0x53dacb(0x212), _0x53dacb(0x1d5), _0x53dacb(0x1de), _0x53dacb(0x210), _0x53dacb(0x314), _0x53dacb(0x1c9), 'webdriver' ], 'string' ) ), Object['assign']( _0x2d8bb4[_0x53dacb(0x270)], _0x58210c( navigator, [_0x53dacb(0x1e1), 'vibrate', _0x53dacb(0x2e2), _0x53dacb(0x292), _0x53dacb(0x390), _0x53dacb(0x38f)], _0x53dacb(0x1ab) ) ), Object[_0x53dacb(0x2a0)](_0x2d8bb4[_0x53dacb(0x270)], _0x58210c(navigator, [_0x53dacb(0x360), _0x53dacb(0x33b)], _0x53dacb(0x28b))), (_0x2d8bb4['navigator'][_0x53dacb(0x398)] = '' + navigator[_0x53dacb(0x398)]) try { document[_0x53dacb(0x188)](_0x53dacb(0x240)), (_0x1c216f = -0xa2 * -0x5 + 0x26 * -0xe8 + -0x11 * -0x1d7) } catch (_0x264380) { _0x1c216f = 0xbc0 + -0x26b + -0xd9 * 0xb } _0x2d8bb4['navigator'][_0x53dacb(0x34b)] = _0x1c216f var _0x5ac61e = _0x53dacb(0x1ea) in window ? 0x2424 + 0x1 * 0xa5c + -0x2e7f : -0x86b * 0x1 + -0x195 + 0xa02 _0x2d8bb4[_0x53dacb(0x270)][_0x53dacb(0x1d6)] = _0x5ac61e } function _0x5abc93() { var _0x279235 = _0x5612de Object['assign']( _0x2d8bb4['window'], _0x58210c( window, [ 'Image', _0x279235(0x309), _0x279235(0x29f), _0x279235(0x399), _0x279235(0x33a), 'external', 'mozRTCPeerConnection', 'postMessage', _0x279235(0x284), _0x279235(0x2de), _0x279235(0x2ff), _0x279235(0x1dc), _0x279235(0x3be), _0x279235(0x2e9) ], _0x279235(0x1ab) ) ), Object[_0x279235(0x2a0)](_0x2d8bb4[_0x279235(0x393)], _0x58210c(window, [_0x279235(0x3c0)], _0x279235(0x28b))), (_0x2d8bb4[_0x279235(0x393)][_0x279235(0x3c2)] = window[_0x279235(0x3c2)][_0x279235(0x290)]) } function _0x5d3845() { var _0x4ceb6d = _0x5612de try { var _0x55434c = document, _0x2f0012 = window[_0x4ceb6d(0x328)], _0x5ac16c = window[_0x4ceb6d(0x306)] >>> (0x1d2c + -0x21 * 0xa7 + -0x1 * 0x7a5), _0x44cace = window[_0x4ceb6d(0x222)] >>> (-0xcd0 + -0x1f70 + 0x162 * 0x20), _0x5953b9 = window[_0x4ceb6d(0x1aa)] >>> (0x5 * 0x2e3 + -0x1 * -0x1f7 + -0x1 * 0x1066), _0x1dfce9 = window[_0x4ceb6d(0x26d)] >>> (0x1545 + -0x8d7 + -0xc6e), _0x29911c = Math[_0x4ceb6d(0x1cf)](window['screenX']), _0x340972 = Math['floor'](window[_0x4ceb6d(0x366)]), _0x4bc0b8 = window[_0x4ceb6d(0x258)] >>> (-0x1 * -0x1548 + -0x21 * -0x7 + -0x162f), _0x39df7d = window[_0x4ceb6d(0x282)] >>> (0x1dc7 * 0x1 + -0x2113 + 0x34c), _0x13b30d = _0x2f0012['availWidth'] >>> (0xc84 + 0x1 * -0x644 + -0x640), _0x3f047e = _0x2f0012[_0x4ceb6d(0x276)] >>> (-0x23c + 0xc * 0x1c4 + -0x12f4 * 0x1), _0x3e7595 = _0x2f0012['width'] >>> (0x61 * 0x4 + -0x2469 + 0x22e5 * 0x1), _0xa6e264 = _0x2f0012[_0x4ceb6d(0x245)] >>> (0x882 + 0x2646 + -0x5d9 * 0x8) return { innerWidth: void (-0xa40 + 0x192e + -0x31 * 0x4e) !== _0x5ac16c ? _0x5ac16c : -(0x135c + -0xd * -0x115 + -0x45 * 0x7c), innerHeight: void (-0x2176 + -0x281 * -0xc + 0x17 * 0x26) !== _0x44cace ? _0x44cace : -(-0x17a1 + 0xe8 * 0x8 + 0x576 * 0x3), outerWidth: void (-0x167c + -0x6f * 0x49 + 0x3623) !== _0x5953b9 ? _0x5953b9 : -(0x3 * -0x795 + 0x4 * -0x53b + 0x2bac), outerHeight: void (-0x26 * -0x5f + -0xf71 + -0x1 * -0x157) !== _0x1dfce9 ? _0x1dfce9 : -(0xebd + -0x18cd + 0x3 * 0x35b), screenX: void (-0xf9 * -0x22 + 0xd3 * -0x2c + 0x332) !== _0x29911c ? _0x29911c : -(-0x188 + -0x24e3 + 0x266c), screenY: void (-0x5 * -0x105 + 0x2 * 0x11fe + -0x2915) !== _0x340972 ? _0x340972 : -(-0x3cc * -0x6 + 0x1561 * 0x1 + -0x2c28), pageXOffset: void (0xb15 + -0x64d * 0x5 + -0x2 * -0xa36) !== _0x4bc0b8 ? _0x4bc0b8 : -(0x647 + -0x1 * -0x1ced + -0x2333), pageYOffset: void (-0x1337 * 0x1 + -0x10c1 + -0x1 * -0x23f8) !== _0x39df7d ? _0x39df7d : -(0x3b * 0x5b + -0x7 * 0x3a6 + 0x492), availWidth: void (-0xd * 0x267 + 0x1a67 + -0x2 * -0x26a) !== _0x13b30d ? _0x13b30d : -(0xe48 + -0x7d * -0x23 + -0x1f5e), availHeight: void (-0x192a + 0x5 * -0x5b3 + 0xf1 * 0x39) !== _0x3f047e ? _0x3f047e : -(0x4 * 0x5b + -0x3 * -0x13 + -0x1a4), sizeWidth: void (-0x1a38 * 0x1 + -0x20cb + 0x1 * 0x3b03) !== _0x3e7595 ? _0x3e7595 : -(-0x663 + -0x2659 + 0x2cbd * 0x1), sizeHeight: void (0x857 * 0x3 + -0x65 * -0xa + -0x1cf7) !== _0xa6e264 ? _0xa6e264 : -(0xafa + 0x305 * 0x5 + -0x1a12), clientWidth: _0x55434c['body'] ? _0x55434c[_0x4ceb6d(0x189)][_0x4ceb6d(0x1a2)] >>> (-0xe38 + 0x1839 + -0xa01) : -(0x1338 + 0x21c1 + 0x69f * -0x8), clientHeight: _0x55434c[_0x4ceb6d(0x189)] ? _0x55434c[_0x4ceb6d(0x189)][_0x4ceb6d(0x3bb)] >>> (-0x1 * 0x156 + 0x31 * 0x43 + -0xb7d) : -(0x1202 + -0x32b + -0xed6), colorDepth: _0x2f0012[_0x4ceb6d(0x17e)] >>> (-0x1d * -0xcb + 0x197 * 0x11 + 0x26 * -0x151), pixelDepth: _0x2f0012[_0x4ceb6d(0x30a)] >>> (-0x254c + 0x469 + 0x20e3 * 0x1) } } catch (_0x35aa5a) { return {} } } function _0x573065() { var _0x109cfa = _0x5612de Object[_0x109cfa(0x2a0)]( _0x2d8bb4[_0x109cfa(0x208)], _0x58210c(document, [_0x109cfa(0x335), _0x109cfa(0x253), 'documentMode'], _0x109cfa(0x33c)) ), Object['assign'](_0x2d8bb4[_0x109cfa(0x208)], _0x58210c(document, [_0x109cfa(0x325), _0x109cfa(0x183), 'images'], _0x109cfa(0x1ab))) } function _0x47f354() { var _0xad51a5 = _0x5612de, _0x5ad193 = {} try { var _0x344158 = document[_0xad51a5(0x260)](_0xad51a5(0x24d))[_0xad51a5(0x2f9)](_0xad51a5(0x26b)), _0x45ab53 = _0x344158[_0xad51a5(0x1d7)](_0xad51a5(0x375)), _0x3724de = _0x344158['getParameter'](_0x45ab53['UNMASKED_VENDOR_WEBGL']), _0x41fa79 = _0x344158[_0xad51a5(0x383)](_0x45ab53[_0xad51a5(0x39e)]) ; (_0x5ad193['vendor'] = _0x3724de), (_0x5ad193[_0xad51a5(0x2c2)] = _0x41fa79) } catch (_0x22684e) { } return _0x5ad193 } function _0x58bcf8() { var _0x3fa932 = _0x5612de, _0xf9ae75 = _0x11a1d6() if (_0xf9ae75) { var _0x3c4406 = { antialias: _0xf9ae75[_0x3fa932(0x1c5)]()[_0x3fa932(0x1a5)] ? -0x1d2e + -0x4b1 + 0x21e0 : -0x1 * -0x87c + 0x4b * 0x49 + -0x5 * 0x5f9, blueBits: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x27e)]), depthBits: _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x252)]), greenBits: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['GREEN_BITS']), maxAnisotropy: _0x39c3d8(_0xf9ae75), maxCombinedTextureImageUnits: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['MAX_COMBINED_TEXTURE_IMAGE_UNITS']), maxCubeMapTextureSize: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x300)]), maxFragmentUniformVectors: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x286)]), maxRenderbufferSize: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x2da)]), maxTextureImageUnits: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['MAX_TEXTURE_IMAGE_UNITS']), maxTextureSize: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x203)]), maxVaryingVectors: _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x264)]), maxVertexAttribs: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75['MAX_VERTEX_ATTRIBS']), maxVertexTextureImageUnits: _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x205)]), maxVertexUniformVectors: _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x19d)]), shadingLanguageVersion: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x179)]), stencilBits: _0xf9ae75['getParameter'](_0xf9ae75[_0x3fa932(0x2bb)]), version: _0xf9ae75[_0x3fa932(0x383)](_0xf9ae75[_0x3fa932(0x201)]) } Object['assign'](_0x2d8bb4['webgl'], _0x3c4406) } Object[_0x3fa932(0x2a0)](_0x2d8bb4[_0x3fa932(0x26b)], _0x47f354()) } function _0x75957() { var _0x122393 = _0x5612de if (window[_0x122393(0x29f)]) { for (var _0x2963d5 = -0x81a + -0xad * -0x1 + 0x76f; _0x2963d5 < -0x1629 + 0x1 * 0x31c + 0x1317; _0x2963d5++) try { return !!new window[_0x122393(0x29f)](_0x122393(0x3b4) + _0x2963d5) && _0x2963d5[_0x122393(0x3ae)]() } catch (_0x2c5722) { } try { return !!new window[_0x122393(0x29f)]('PDF.PdfCtrl.1') && '4' } catch (_0x1be01e) { } try { return !!new window[_0x122393(0x29f)](_0x122393(0x345)) && '7' } catch (_0x19cffa) { } } return '0' } function _0x1555d9() { return { plugin: _0x30412e(), pv: _0x75957() } } function _0x1f01ce(_0x371dd1) { var _0x5c76bb = _0x5612de try { var _0xf71d16 = window[_0x371dd1], _0x28a4d1 = _0x5c76bb(0x1f9) return _0xf71d16[_0x5c76bb(0x1c4)](_0x28a4d1, _0x28a4d1), _0xf71d16[_0x5c76bb(0x2c3)](_0x28a4d1), !(0x1e7a + -0x1824 + 0x2 * -0x32b) } catch (_0x1dd803) { return !(0x6e5 + 0x599 * -0x2 + -0x1 * -0x44e) } } function _0x3ffe15() { return w_0x5c3140( '484e4f4a403f5243003c20117d3adeac000000004e770f390000003a030014000102110100070000430147000b11000103012f170001354902110100070001430147000e110001030103012b2f17000135491100014200020c45464a48457a5d465b484e4c0e5a4c5a5a4046477a5d465b484e4c', { get 0x0() { return _0x1f01ce }, 0x1: arguments }, this ) } function _0x252788(_0x468bb4, _0x392758, _0x269720) { var _0x16947c = _0x5612de for ( var _0x4dea11 = 0x1 * 0x1705 + 0x29 * -0xbf + 0x72 * 0x11, _0x1f88e5 = 0x65 * -0x7 + 0xb50 + -0x88d; _0x1f88e5 < _0x392758['length']; _0x1f88e5++ ) { var _0x1dd5f9 = _0x2195cd(_0x468bb4, _0x392758[_0x1f88e5]) if (_0x1dd5f9 && ((_0x4dea11 |= _0x1dd5f9 << (_0x269720 + _0x1f88e5)), _0x269720 + _0x1f88e5 >= 0xd5a + 0x7c + -0x1 * 0xdb6)) { console[_0x16947c(0x310)]('abort\x2032') break } } return _0x4dea11 } function _0x484054() { return w_0x5c3140( '484e4f4a403f5243002c3b0a6f4f88290000000044c410000000011f1101001400010700000700010700020700030700040700050700060700070700080700090c000a14000207000a14000307000b14000407000a110101110004163e000414000a413d00d11100014a07000c1307000d43010300131400050c0000140006030014000711000711000207000e13274700691100014a07000f130700104301140008110002110007131400091100084a0700111307001207001311000918430249110004070014181100091807001518110008070016161100054a070017131100084301491100064a07001813110008430149170007214945ff891101011100041317000335490300170007354911000711000207000e132747001a1100054a0700191311000611000713430149170007214945ffd84111000342001a037e617e037e617d037e617c037e617b037e617a037e6179037e6178037e6177037e6176037d617f0014262b20213b242120382138272e3b263c3b27263c14282a3b0a232a222a213b3c0d361b2e28012e222a04272a2e2b06232a21283b270d2c3d2a2e3b2a0a232a222a213b063c2c3d263f3b0c3c2a3b0e3b3b3d262d3a3b2a08232e21283a2e282a0a052e392e1c2c3d263f3b02726d016d043b2a373b0b2e3f3f2a212b0c2726232b043f3a3c270b3d2a2220392a0c2726232b', { get 0x0() { return document }, get 0x1() { return window }, 0x2: arguments }, this ) } ; (_0x2d8bb4[_0x5612de(0x270)] = {}), (_0x2d8bb4[_0x5612de(0x23e)] = {}), (_0x2d8bb4[_0x5612de(0x393)] = {}), (_0x2d8bb4[_0x5612de(0x26b)] = {}), (_0x2d8bb4['document'] = {}), (_0x2d8bb4[_0x5612de(0x328)] = {}), (_0x2d8bb4[_0x5612de(0x1ba)] = {}), (_0x2d8bb4['custom'] = {}) var _0x548676 = null function _0x491716() { var _0x4f58c9 = _0x5612de return w_0x5c3140( _0x4f58c9(0x174), { get 0x0() { return self }, get 0x1() { return window }, get 0x2() { return parent }, 0x3: arguments }, this ) } function _0x2d2578() { !(function () { var _0x236733 = w_0x25f3, _0x460c07 = {}, _0x3606e1 = navigator[_0x236733(0x359)] || navigator[_0x236733(0x2f0)] if (_0x3606e1) { try { ; (_0x460c07[_0x236733(0x3ac)] = _0x3606e1[_0x236733(0x3ac)] ? 0x147a + -0x5 * 0x60f + 0x9d2 : -0x169c + 0x26d6 + -0x1038), (_0x460c07[_0x236733(0x213)] = Math[_0x236733(0x369)]((0x31 * 0x75 + 0x14c7 + -0x2ac8) * _0x3606e1[_0x236733(0x213)])), (_0x460c07[_0x236733(0x2b0)] = '' + _0x3606e1[_0x236733(0x2b0)]), (_0x460c07[_0x236733(0x191)] = '' + _0x3606e1['dischargingTime']) } catch (_0x2c301c) { } ; (_0x2d8bb4[_0x236733(0x359)] = {}), Object[_0x236733(0x2a0)](_0x2d8bb4[_0x236733(0x359)], _0x460c07) } else { if (_0x236733(0x384) != typeof navigator && navigator[_0x236733(0x1b2)]) try { navigator[_0x236733(0x1b2)]()[_0x236733(0x1ed)](function (_0x369fc5) { var _0x34e3e9 = _0x236733 try { ; (_0x460c07[_0x34e3e9(0x3ac)] = _0x369fc5[_0x34e3e9(0x3ac)] ? 0x20aa + -0x11 * -0x86 + 0x1 * -0x298f : 0xd51 + 0x152c + 0xd * -0x2a7), (_0x460c07[_0x34e3e9(0x213)] = Math[_0x34e3e9(0x369)]( (0x1205 + -0x41 * 0x32 + -0x3 * 0x1a5) * _0x369fc5[_0x34e3e9(0x213)] )), (_0x460c07[_0x34e3e9(0x2b0)] = '' + _0x369fc5[_0x34e3e9(0x2b0)]), (_0x460c07[_0x34e3e9(0x191)] = '' + _0x369fc5['dischargingTime']) } catch (_0x2f63d1) { } ; (_0x2d8bb4['battery'] = {}), Object[_0x34e3e9(0x2a0)](_0x2d8bb4[_0x34e3e9(0x359)], _0x460c07) }) } catch (_0xfc012d) { } } })(), 'undefined' != typeof Promise && (_0x548676 = new Promise(function (_0x1df02e) { try { _0x5bbaf0()['then'](function (_0x27ab47) { var _0xbee19f = w_0x25f3 Object[_0xbee19f(0x2a0)](_0x2d8bb4['wID'], { rtcIP: _0x27ab47 }) }) } catch (_0x7bc12a) { } _0x1df02e('') })) } function _0x5c328e() { var _0x378ae2 = _0x5612de return w_0x5c3140( _0x378ae2(0x1ad), { get 0x0() { return window }, get 0x1() { return navigator }, get 0x2() { var _0xa78dc5 = _0x378ae2 return _0xa78dc5(0x384) != typeof InstallTrigger ? InstallTrigger : void (0x26ae * 0x1 + -0xad * 0x2e + -0x6c * 0x12) }, 0x3: Object, get 0x4() { return _0x241339 }, get 0x5() { return _0x2d8bb4 }, get 0x6() { return document }, 0x7: Promise, 0x8: Date, get 0x9() { return _0x252788 }, get 0xa() { return _0x5011f8 }, get 0xb() { return _0x4f323e }, get 0xc() { return _0x5090f5 }, 0xd: Math, get 0xe() { return _0x3ffe15 }, get 0xf() { return _0x18b4be }, get 0x10() { return _0x484054 }, get 0x11() { return _0x491716 }, get 0x12() { return _0x462335 }, get 0x13() { return _0x24dc34 }, get 0x14() { return _0x6caf }, get 0x15() { return _0x2d2578 }, get 0x16() { return _0x3a2b92 }, get 0x17() { return _0x5abc93 }, get 0x18() { return _0x573065 }, get 0x19() { return _0x58bcf8 }, get 0x1a() { return _0x1555d9 }, get 0x1b() { return _0x5d3845 }, 0x1c: parseInt, get 0x1d() { return _0x3d13cf }, get 0x1e() { return _0x4a2daf }, get 0x1f() { return _0x641e3d }, 0x20: JSON, get 0x21() { return _0x48a082 }, get 0x22() { return _0x4df596 }, get 0x23() { return _0x5dde58 }, get 0x24() { return _0x548676 }, get 0x25() { return _0x29a5ac }, 0x26: arguments }, this ) } function _0x25a792(_0x2f25f2) { var _0x329005 = _0x5612de return _0x462335[_0x329005(0x185)] && _0x462335[_0x329005(0x185)][_0x329005(0x2dc)] && -(-0x4f2 * 0x5 + 0x254f + -0xc94) !== _0x2f25f2[_0x329005(0x2c5)](_0x462335[_0x329005(0x185)][_0x329005(0x2dc)]) ? _0x39693d['sec'] : _0x39693d[_0x329005(0x1b4)] } function _0xd287a1(_0x35260d) { var _0x241816 = _0x5612de, _0x40ac17 = _0x462335[_0x241816(0x185)][_0x241816(0x2dc)] return !(!_0x40ac17 || !_0x35260d || -(0x116 * -0x2 + -0x1af8 * -0x1 + -0x18cb) === _0x35260d[_0x241816(0x2c5)](_0x40ac17)) } function _0x2b13af(_0x52c947) { var _0x221375 = _0x5612de, _0x7eff84 = _0x52c947 decodeURIComponent(_0x52c947) === _0x52c947 && (_0x7eff84 = encodeURI(_0x52c947)) var _0x5e1d88 = _0x7eff84[_0x221375(0x2c5)]('?') if (_0x5e1d88 > 0x1673 * 0x1 + 0x2150 + -0x37c3) { var _0xc7170 = _0x7eff84[_0x221375(0x3a7)](-0x80c + 0x71e * 0x2 + -0x630, _0x5e1d88 + (0x2 * 0x919 + 0x4 * -0x931 + 0x1293)), _0x8fbad9 = _0x7eff84[_0x221375(0x3a7)](_0x5e1d88 + (-0x1de4 + -0x2 * -0x1163 + 0x4e1 * -0x1)) _0x7eff84 = _0xc7170 + _0x8fbad9[_0x221375(0x342)]('\x27')['join'](_0x221375(0x37e)) } return _0x7eff84 } function _0x1958a5(_0x42413b, _0x5e3de6) { var _0x406220 = _0x5612de for (var _0x32045a = '', _0xbe63df = '', _0x5623ae = 0x5f6 + -0x220e + 0x1c18; _0x5623ae < _0x5e3de6[_0x406220(0x259)]; _0x5623ae++) _0x5623ae % (0x951 + 0xb15 + 0x105 * -0x14) == -0x10de + 0x15 * 0x185 + 0x1 * -0xf0b ? (_0xbe63df = _0x5e3de6[_0x5623ae]) : (_0x32045a += '&' + _0xbe63df + '=' + _0x5e3de6[_0x5623ae]) var _0x4ddc33 = _0x42413b if (_0x32045a[_0x406220(0x259)] > -0x135d + 0x8e1 + -0x2c * -0x3d) { var _0x50fb42 = -(0x2 * -0x1252 + 0x13 * 0x85 + 0x95 * 0x2e) === _0x42413b['indexOf']('?') ? '?' : '&' _0x4ddc33 = _0x42413b + _0x50fb42 + _0x32045a[_0x406220(0x3a7)](0x324 + -0xf1 * -0x17 + 0x1 * -0x18ca) } return _0x4ddc33 } function _0x288415(_0x5a419e) { var _0x259f53 = _0x5612de, _0x4465ef = _0x5a419e['indexOf']('?') return -(-0x78c + -0x1a4c + -0x6c5 * -0x5) !== _0x4465ef ? _0x5a419e[_0x259f53(0x3a7)](_0x4465ef + (0x907 + 0x137b * 0x1 + -0x1c81)) : '' } function _0x6a7375(_0x2a9a57) { var _0x447596 = _0x5612de for (var _0x1ca622 = -0x16a3 * -0x1 + 0x87b + -0x1f1e; _0x1ca622 < _0x462335['_enablePathListRegex']['length']; _0x1ca622++) if (_0x462335[_0x447596(0x1a9)][_0x1ca622]['test'](_0x2a9a57)) return !(-0x5ed + -0x3d * -0x41 + -0x990) return !(-0x1 * -0x26ff + -0x11c1 * 0x1 + -0x153d) } function _0x7d8404(_0x34967f) { var _0x5e578e = _0x5612de return _0x5e578e(0x186) === _0x34967f || 'application/json' === _0x34967f } function _0x3af1be() { var _0x1347f7 = _0x5612de return w_0x5c3140( _0x1347f7(0x368), { get 0x0() { return window }, get 0x1() { return _0x6a7375 }, get 0x2() { return _0x6caf }, get 0x3() { return _0x1958a5 }, get 0x4() { return _0x2b13af }, get 0x5() { return _0x288415 }, get 0x6() { return _0x8edc3d }, get 0x7() { return _0x462335 }, get 0x8() { return _0x45e0e9 }, get 0x9() { return _0x7d8404 }, get 0xa() { return _0x1294ff }, get 0xb() { return _0x20cbf3 }, get 0xc() { return _0x45b94b }, get 0xd() { return _0x572e48 }, get 0xe() { return _0xd287a1 }, get 0xf() { return _0x25a792 }, get 0x10() { return _0x39693d }, get 0x11() { return _0x1f42cb }, get 0x12() { return _0x556182 }, get 0x13() { return setTimeout }, get 0x14() { return _0x5c328e }, 0x15: arguments, 0x16: RegExp }, this ) } var _0x3c4266 = _0x5612de(0x384) != typeof URL && URL instanceof Object, _0x3311d7 = 'undefined' != typeof Request && Request instanceof Object, _0x4f1fa4 = 'undefined' != typeof Headers && Headers instanceof Object function _0x415adb() { var _0x51ab32 = _0x5612de return window[_0x51ab32(0x197)] } function _0x1d82ac() { var _0x2340b7 = _0x5612de return w_0x5c3140( _0x2340b7(0x234), { get 0x0() { return _0x415adb }, get 0x1() { return window }, get 0x2() { return _0xd287a1 }, get 0x3() { return _0x25a792 }, get 0x4() { return _0x39693d }, get 0x5() { return _0x6caf }, get 0x6() { return _0x1f42cb }, get 0x7() { return _0x556182 }, get 0x8() { return setTimeout }, get 0x9() { return _0x5c328e }, get 0xa() { return _0x3311d7 }, get 0xb() { return Request }, get 0xc() { return _0x3c4266 }, get 0xd() { return URL }, get 0xe() { return _0x6a7375 }, get 0xf() { return _0x1958a5 }, get 0x10() { return _0x2b13af }, get 0x11() { return _0x288415 }, get 0x12() { return _0x8edc3d }, get 0x13() { return _0x462335 }, get 0x14() { return _0x45e0e9 }, get 0x15() { return _0xb48e77 }, get 0x16() { return _0x7d8404 }, get 0x17() { return _0x1294ff }, get 0x18() { return _0x20cbf3 }, get 0x19() { return _0x45b94b }, get 0x1a() { return _0x572e48 }, 0x1b: arguments }, this ) } function _0xb48e77(_0x29caaf, _0xa4ab82) { var _0x1cf8d6 = _0x5612de, _0x314297 = '' if (_0x3311d7 && _0x29caaf instanceof Request) { var _0x1f374d = _0x29caaf[_0x1cf8d6(0x35b)][_0x1cf8d6(0x32b)](_0x1cf8d6(0x228)) return _0x1f374d && (_0x314297 = _0x1f374d), _0x314297 } if (_0xa4ab82 && _0xa4ab82[_0x1cf8d6(0x35b)]) { if (_0x4f1fa4 && _0xa4ab82[_0x1cf8d6(0x35b)] instanceof Headers) { var _0x4dff82 = _0xa4ab82[_0x1cf8d6(0x35b)][_0x1cf8d6(0x32b)](_0x1cf8d6(0x228)) return _0x4dff82 && (_0x314297 = _0x4dff82), _0x314297 } if (_0xa4ab82['headers'] instanceof Array) { for (var _0x6ae47c = 0xd20 + 0x699 * -0x5 + -0x13dd * -0x1; _0x6ae47c < _0xa4ab82['headers'][_0x1cf8d6(0x259)]; _0x6ae47c++) if (_0x1cf8d6(0x228) == _0xa4ab82[_0x1cf8d6(0x35b)][_0x6ae47c][-0x12f6 + -0x207f + 0x1127 * 0x3]['toLowerCase']()) return _0xa4ab82[_0x1cf8d6(0x35b)][_0x6ae47c][-0xaa2 + -0xe0e + 0x18b1] } if (_0xa4ab82[_0x1cf8d6(0x35b)] instanceof Object) { for ( var _0x1506c8 = -0x1ce4 + 0x8dc + 0xa04 * 0x2, _0x32fecb = Object['keys'](_0xa4ab82['headers']); _0x1506c8 < _0x32fecb[_0x1cf8d6(0x259)]; _0x1506c8++ ) { var _0x228b3d = _0x32fecb[_0x1506c8] if ('content-type' === _0x228b3d['toLowerCase']()) return _0xa4ab82[_0x1cf8d6(0x35b)][_0x228b3d] } return _0x314297 } } } function _0x1294ff(_0x1475ff, _0x5700d1, _0x563b6f) { var _0x383b2a = _0x5612de if (null == _0x563b6f || '' === _0x563b6f) return _0x1475ff if (((_0x563b6f = _0x563b6f[_0x383b2a(0x3ae)]()), _0x383b2a(0x186) === _0x5700d1)) { _0x1475ff[_0x383b2a(0x336)] = !(0xfc + -0x22d4 + 0x21d8) var _0x38ceac = _0x563b6f[_0x383b2a(0x342)]('&'), _0x1b01b6 = {} if (_0x38ceac) { for (var _0x4c4745 = -0x29 * -0xd3 + 0x1 * 0xa01 + -0x2bcc; _0x4c4745 < _0x38ceac['length']; _0x4c4745++) _0x1b01b6[_0x38ceac[_0x4c4745][_0x383b2a(0x342)]('=')[0x2 * -0x391 + -0x1 * -0x99f + -0x27d]] = decodeURIComponent( _0x38ceac[_0x4c4745][_0x383b2a(0x342)]('=')[0x1e44 + -0x14e3 * -0x1 + -0x3326] ) } _0x1475ff[_0x383b2a(0x189)] = _0x1b01b6 } else _0x1475ff[_0x383b2a(0x189)] = JSON['parse'](_0x563b6f) return _0x1475ff } function _0x45e0e9(_0x2d3284, _0xb8d78) { var _0x521f3f = _0x5612de, _0x3496a3 = _0xb8d78 if (_0x462335[_0x521f3f(0x18d)][_0x521f3f(0x259)] > 0x1f8f * 0x1 + -0x1 * 0x21dd + 0xa * 0x3b) for ( var _0x335ec5 = 0xb * -0xd3 + -0x1977 * 0x1 + -0x41 * -0x88; _0x335ec5 < _0x462335[_0x521f3f(0x18d)][_0x521f3f(0x259)]; _0x335ec5++ ) { var _0x3f8686 = _0x462335[_0x521f3f(0x18d)][_0x335ec5][-0x2023 + 0xcb * -0x10 + -0x1cb * -0x19] if (_0x3f8686[_0x521f3f(0x22b)](_0xb8d78)) { ; (_0x3496a3 = _0xb8d78[_0x521f3f(0x377)](_0x3f8686, _0x462335[_0x521f3f(0x18d)][_0x335ec5][0x1a12 * -0x1 + 0x2361 + -0x94e])), _0x2d3284 && _0x3d40ff[_0x521f3f(0x397)]['call']( _0x2d3284, _0x521f3f(0x243), _0x521f3f(0x223) + _0xb8d78 + '\x0aREWRITED:\x20' + _0x3496a3 ) break } } return (_0x3496a3 = _0x2b13af(_0x3496a3)) } function _0x344a4d() { var _0x1b8e41 = _0x5612de return w_0x5c3140( _0x1b8e41(0x20d), { get 0x0() { return window }, get 0x1() { return _0x6a7375 }, get 0x2() { return _0x6caf }, get 0x3() { return _0x1958a5 }, get 0x4() { return _0x2b13af }, get 0x5() { return _0x288415 }, get 0x6() { return _0x8edc3d }, 0x7: arguments }, this ) } function _0x3f720d() { _0x3af1be(), _0x1d82ac(), _0x344a4d() } function _0x3bfecb(_0x4b21ed) { var _0x3a0ee2 = _0x5612de ; (this[_0x3a0ee2(0x341)] = 'ConfigException'), (this[_0x3a0ee2(0x312)] = _0x4b21ed) } var _0x589057 = { cn: { host: _0x5612de(0x2c9) } }, _0x2bbf08 = [_0x5612de(0x30c)], _0x3d70a4 function _0x43f5a3(_0x5a985f) { var _0x20ecf9 = _0x5612de, _0x3c43cc = '' return { host: (_0x3c43cc = _0x5a985f[_0x20ecf9(0x1b6)] || _0x5a985f[_0x20ecf9(0x1ae)] ? _0x5a985f[_0x20ecf9(0x1b3)] : _0x589057[_0x5a985f[_0x20ecf9(0x224)]][_0x20ecf9(0x2dc)]), pathList: _0x2bbf08, reportUrl: _0x3c43cc + _0x2bbf08[0x1d7 * 0x7 + 0x1073 + -0x1d54] } } var _0x383bd7 = !(0x244 * 0xb + -0x16a * -0x4 + -0x1e93), _0xd39ee2, _0x9e520d function _0x53ee31(_0x817028) { var _0x5d5e8d = _0x5612de return w_0x5c3140( _0x5d5e8d(0x34f), { 0x0: Object, 0x1: Math, get 0x2() { return _0x3bfecb }, get 0x3() { return _0x6caf }, get 0x4() { return _0x462335 }, get 0x5() { return _0x43f5a3 }, get 0x6() { return setTimeout }, get 0x7() { return _0x5c328e }, get 0x8() { return _0x3d70a4 }, set 0x8(_0x5982f0) { _0x3d70a4 = _0x5982f0 }, get 0x9() { return clearInterval }, get 0xa() { return setInterval }, get 0xb() { return _0x450b73 }, get 0xc() { return _0x1a39c4 }, get 0xd() { return _0x3f720d }, get 0xe() { return _0x59992f }, get 0xf() { return _0x39d569 }, get 0x10() { return _0x1dbe74 }, get 0x11() { return _0x383bd7 }, set 0x11(_0x488bc8) { _0x383bd7 = _0x488bc8 }, get 0x12() { return _0x18707d }, get 0x13() { return _0x1c3b6d }, 0x14: arguments, 0x15: _0x817028 }, this ) } function _0x3498af(_0x3e9bb9) { } function _0x59992f(_0x10dd97) { var _0x1beab7 = _0x5612de for (var _0x52c469 = 0xb * -0x262 + -0x606 + 0x101e * 0x2; _0x52c469 < _0x10dd97[_0x1beab7(0x259)]; _0x52c469++) _0x10dd97[_0x52c469] && _0x462335['_enablePathListRegex']['push'](new RegExp(_0x10dd97[_0x52c469])) } function _0x39d569(_0x51ab06) { var _0x59d7a1 = _0x5612de if (void (-0x11c8 * 0x1 + 0x1fa2 * 0x1 + -0xdda) !== _0x51ab06) { for (var _0x3e2076 = -0x3ab * -0x5 + -0x19d4 + 0x1b * 0x47; _0x3e2076 < _0x51ab06[_0x59d7a1(0x259)]; _0x3e2076++) _0x462335[_0x59d7a1(0x18d)][_0x59d7a1(0x36e)]([ new RegExp(_0x51ab06[_0x3e2076][-0xfb * -0x1 + 0x9a7 * 0x4 + -0x5 * 0x7eb]), _0x51ab06[_0x3e2076][-0x57 * 0x55 + 0x1c99 * 0x1 + 0x4b] ]) } } function _0x32e4a6() { var _0x494ee9 = _0x5612de return window[_0x494ee9(0x318)] || '' } function _0x1be1e1(_0x58db04) { var _0x32bdb2 = _0x5612de, _0x4558be = _0x6caf[_0x32bdb2(0x323)], _0x4ab91a = -0x5d * 0x5e + -0xb06 + -0x47 * -0xa3 _0x32bdb2(0x2b6) === _0x58db04 && (_0x4ab91a = 0x1754 + 0xd0 * 0x4 + -0x1a93), _0x32bdb2(0x285) === _0x58db04 && (_0x4ab91a = -0x146 * -0x13 + 0x13 * 0xef + -0x29ed) var _0x1741bb = { ts: new Date()[_0x32bdb2(0x16d)](), v: _0x4ab91a } _0x4558be[_0x32bdb2(0x36e)](_0x1741bb) } function _0x4de7ef() { var _0x45ce69 = _0x5612de, _0x5c1967, _0x586941 void (0xbc1 + 0x1 * 0x1309 + -0x1eca) !== document[_0x45ce69(0x285)] ? (_0x45ce69(0x285), (_0x586941 = _0x45ce69(0x1a0)), (_0x5c1967 = _0x45ce69(0x1f6))) : void (0x2056 + 0x2306 + -0x435c) !== document[_0x45ce69(0x15f)] ? (_0x45ce69(0x15f), (_0x586941 = _0x45ce69(0x1c8)), (_0x5c1967 = _0x45ce69(0x33f))) : void (0x68 * 0x53 + 0x3c7 * 0x3 + -0x2d0d) !== document[_0x45ce69(0x2c6)] ? (_0x45ce69(0x2c6), (_0x586941 = _0x45ce69(0x2cc)), (_0x5c1967 = _0x45ce69(0x1a4))) : void (-0x1bd7 + 0xc9 * -0x2b + 0x3d9a) !== document[_0x45ce69(0x22a)] && (_0x45ce69(0x22a), (_0x586941 = _0x45ce69(0x322)), (_0x5c1967 = _0x45ce69(0x166))), document[_0x45ce69(0x2f6)]( _0x586941, function () { _0x1be1e1(document[_0x5c1967]) }, !(0x1088 + 0x18c2 + 0xdc3 * -0x3) ), _0x1be1e1(document[_0x5c1967]) } function _0x3ff3f1() { _0x58c311() } function _0x4c727e() { var _0x3f5094 = _0x5612de function _0x115c6a(_0x2162b2) { var _0x4cc12e = w_0x25f3 _0x462335['triggerUnload'] || ((_0x462335[_0x4cc12e(0x204)] = !(0x1 * -0x632 + 0x3 * -0xb71 + -0x1c3 * -0x17)), _0x3ff3f1()) } window && window[_0x3f5094(0x2f6)] && (window[_0x3f5094(0x2f6)](_0x3f5094(0x37d), _0x115c6a), window[_0x3f5094(0x2f6)](_0x3f5094(0x29b), _0x115c6a)) } function _0x5b850b() { var _0x4d0be4 = _0x5612de for ( var _0x35a39e = document[_0x4d0be4(0x272)][_0x4d0be4(0x342)](';'), _0x3046a3 = [], _0x58914c = -0x923 + -0x66a * -0x5 + -0x16ef; _0x58914c < _0x35a39e[_0x4d0be4(0x259)]; _0x58914c++ ) if (_0x4d0be4(0x3b5) == (_0x3046a3 = _0x35a39e[_0x58914c][_0x4d0be4(0x342)]('='))[-0x7cd * -0x1 + -0x1678 + 0xeab]['trim']()) { _0x6caf[_0x4d0be4(0x3b5)] = _0x3046a3[0x200f * -0x1 + 0x926 + 0x16ea] break } } function _0x498349(_0x5efcd6) { return new _0x53ee31(_0x5efcd6) } function _0x475194(_0x56e1e3) { ; -0xa7f + -0xb * 0x18a + 0x1b6d === _0x56e1e3 // setTimeout(_0x5047d8, 0x1 * -0xb55 + -0x1031 + 0x1bea * 0x1) : -0xef1 + -0xfd3 * -0x1 + -0xe1 === _0x56e1e3 && setTimeout(_0x5c328e, 0x6 * 0x38d + -0x49 * -0x2b + -0x95 * 0x39); } function _0x4a4111(_0x2ba688, _0x1e135c) { var _0x18e9b1 = _0x5612de ; -0xfab + 0x9 * -0x2a2 + 0x275e === _0x2ba688 && (_0x462335[_0x18e9b1(0x34a)] = Object['assign']({}, _0x462335[_0x18e9b1(0x34a)], _0x1e135c)) } function _0x271dea(_0x20563e) { void (-0x1aa2 + -0x2407 + 0x3 * 0x14e3) !== _0x20563e && '' != _0x20563e && (_0x6caf['ttwid'] = _0x20563e) } function _0x3a4a1a(_0x5b82b5) { var _0x30adbb = _0x5612de void (0xb * -0x17d + -0x227d + 0x32dc) !== _0x5b82b5 && '' != _0x5b82b5 && (_0x6caf[_0x30adbb(0x316)] = _0x5b82b5) } function _0x3f0a66(_0x53e069) { var _0x38d5b6 = _0x5612de void (-0x7eb * 0x3 + 0xc4 * 0x2 + -0x1 * -0x1639) !== _0x53e069 && '' != _0x53e069 && (_0x6caf[_0x38d5b6(0x339)] = _0x53e069) } ; (_0x53ee31[_0x5612de(0x344)][_0x5612de(0x1a3)] = _0x5c2014), (_0x53ee31[_0x5612de(0x344)]['getReferer'] = _0x32e4a6), (_0x53ee31[_0x5612de(0x344)]['setUserMode'] = _0x3498af), (_0xd39ee2 = _0x24dc34(_0x45b94b['refererKey']) || ''), _0x2ecc5a(_0x45b94b['refererKey']), _0x5612de(0x2d6) === _0xd39ee2 ? (_0xd39ee2 = '') : '' === _0xd39ee2 && (_0xd39ee2 = document[_0x5612de(0x2fa)]), _0xd39ee2 && (window[_0x5612de(0x318)] = _0xd39ee2), (_0x9e520d = _0x5141ac()), _0x9e520d && ((_0x6caf[_0x5612de(0x2b4)] = _0x9e520d), (_0x6caf['msStatus'] = _0x39693d['asgw'])), // setTimeout(function () { // _0x18a9f7(), // _0x1dbe74(), // _0x4de7ef(), // _0x4c727e(), // _0x21fa28(); // }, -0x1a83 + 0x15ee + -0xd * -0x141), _0x5b850b(), _0x59992f([_0x5612de(0x30c)]) var _0x1649bc = !(-0xc6b * -0x1 + -0x2315 + 0x16aa) crawler = _0x5c2014 ; (_0x1d18f2['frontierSign'] = _0x5c2014), (_0x1d18f2[_0x5612de(0x2e8)] = _0x32e4a6), (_0x1d18f2[_0x5612de(0x3b9)] = _0x498349), (_0x1d18f2[_0x5612de(0x1f8)] = _0x1649bc), (_0x1d18f2['report'] = _0x475194), (_0x1d18f2[_0x5612de(0x298)] = _0x4a4111), (_0x1d18f2[_0x5612de(0x1a7)] = _0x3a4a1a), (_0x1d18f2['setTTWebidV2'] = _0x3f0a66), (_0x1d18f2[_0x5612de(0x244)] = _0x271dea), (_0x1d18f2[_0x5612de(0x378)] = _0x3498af), Object['defineProperty'](_0x1d18f2, _0x5612de(0x3bd), { value: !(0x1 * 0x2069 + -0x1403 + -0xc66) }) }) } function get_sign(md5) { let data = { 'X-MS-STUB': md5 } return crawler(data)['X-Bogus'] } return get_sign(msStub) } '''; static const String defaultUserAgent = DouyinSite.kDefaultUserAgent; static String getAbogusUrl(String url, String userAgent) { JsRuntime flutterJs = JsRuntime( memoryLimit: 4 * 1024 * 1024, maxStackSize: 64 * 1024, ); final msToken = generateMsToken(107); var params = ('$url&msToken=$msToken').split('?')[1]; var query = params.contains("?") ? params.split("?")[1] : params; var jsCode = kABogus; flutterJs.eval(jsCode); // 执行getABogus函数 var aBogus = flutterJs.eval("getABogus('$query', '$userAgent')"); flutterJs.dispose(); var newUrl = '$url&msToken=${Uri.encodeComponent(msToken)}&a_bogus=${Uri.encodeComponent(aBogus)}'; return newUrl; } static String getSignature(String roomId, String uniqueId) { JsRuntime flutterJs = JsRuntime( memoryLimit: 4 * 1024 * 1024, maxStackSize: 128 * 1024, ); flutterJs.eval(kWebMsSDK); var msStub = getMsStub(roomId, uniqueId); var signature = flutterJs.eval( "getMSSDKSignature('$msStub','$defaultUserAgent')", ); // 如果signature中包含-或=,重新生成 while (signature.contains('-') || signature.contains('=')) { signature = flutterJs.eval( "getMSSDKSignature('$msStub','$defaultUserAgent')", ); } flutterJs.dispose(); return signature; } static String getMsStub(String roomId, String uniqueId) { final params = { "live_id": "1", "aid": "6383", "version_code": 180800, "webcast_sdk_version": "1.3.0", "room_id": roomId, "sub_room_id": "", "sub_channel_id": "", "did_rule": "3", "user_unique_id": uniqueId, "device_platform": "web", "device_type": "", "ac": "", "identity": "audience", }; final sigParams = params.entries .map((e) => "${e.key}=${e.value}") .join(','); // 需要导入crypto库: import 'package:crypto/crypto.dart'; final bytes = sigParams.codeUnits; final digest = md5.convert(bytes); return digest.toString(); } static String generateMsToken(int length) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; final random = Random.secure(); return List.generate( length, (_) => characters[random.nextInt(characters.length)], ).join(''); } } ================================================ FILE: simple_live_core/lib/src/scripts/douyu_sign.dart ================================================ import 'package:dart_quickjs/dart_quickjs.dart'; class DouyuSign { static const String kCryptoJs = r''' !function(t,e){"object"==typeof exports?module.exports=exports=e():"function"==typeof define&&define.amd?define([],e):t.CryptoJS=e()}(this,function(){var h,t,e,r,i,n,f,o,s,c,a,l,d,m,x,b,H,z,A,u,p,_,v,y,g,B,w,k,S,C,D,E,R,M,F,P,W,O,I,U,K,X,L,j,N,T,q,Z,V,G,J,$,Q,Y,tt,et,rt,it,nt,ot,st,ct,at,ht,lt,ft,dt,ut,pt,_t,vt,yt,gt,Bt,wt,kt,St,bt=bt||function(l){var t;if("undefined"!=typeof window&&window.crypto&&(t=window.crypto),!t&&"undefined"!=typeof window&&window.msCrypto&&(t=window.msCrypto),!t&&"undefined"!=typeof global&&global.crypto&&(t=global.crypto),!t&&"function"==typeof require)try{t=require("crypto")}catch(t){}function i(){if(t){if("function"==typeof t.getRandomValues)try{return t.getRandomValues(new Uint32Array(1))[0]}catch(t){}if("function"==typeof t.randomBytes)try{return t.randomBytes(4).readInt32LE()}catch(t){}}throw new Error("Native crypto module could not be used to get secure random number.")}var r=Object.create||function(t){var e;return n.prototype=t,e=new n,n.prototype=null,e};function n(){}var e={},o=e.lib={},s=o.Base={extend:function(t){var e=r(this);return t&&e.mixIn(t),e.hasOwnProperty("init")&&this.init!==e.init||(e.init=function(){e.$super.init.apply(this,arguments)}),(e.init.prototype=e).$super=this,e},create:function(){var t=this.extend();return t.init.apply(t,arguments),t},init:function(){},mixIn:function(t){for(var e in t)t.hasOwnProperty(e)&&(this[e]=t[e]);t.hasOwnProperty("toString")&&(this.toString=t.toString)},clone:function(){return this.init.prototype.extend(this)}},f=o.WordArray=s.extend({init:function(t,e){t=this.words=t||[],this.sigBytes=null!=e?e:4*t.length},toString:function(t){return(t||a).stringify(this)},concat:function(t){var e=this.words,r=t.words,i=this.sigBytes,n=t.sigBytes;if(this.clamp(),i%4)for(var o=0;o>>2]>>>24-o%4*8&255;e[i+o>>>2]|=s<<24-(i+o)%4*8}else for(o=0;o>>2]=r[o>>>2];return this.sigBytes+=n,this},clamp:function(){var t=this.words,e=this.sigBytes;t[e>>>2]&=4294967295<<32-e%4*8,t.length=l.ceil(e/4)},clone:function(){var t=s.clone.call(this);return t.words=this.words.slice(0),t},random:function(t){for(var e=[],r=0;r>>2]>>>24-n%4*8&255;i.push((o>>>4).toString(16)),i.push((15&o).toString(16))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>3]|=parseInt(t.substr(i,2),16)<<24-i%8*4;return new f.init(r,e/2)}},h=c.Latin1={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>24-n%4*8&255;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>2]|=(255&t.charCodeAt(i))<<24-i%4*8;return new f.init(r,e)}},d=c.Utf8={stringify:function(t){try{return decodeURIComponent(escape(h.stringify(t)))}catch(t){throw new Error("Malformed UTF-8 data")}},parse:function(t){return h.parse(unescape(encodeURIComponent(t)))}},u=o.BufferedBlockAlgorithm=s.extend({reset:function(){this._data=new f.init,this._nDataBytes=0},_append:function(t){"string"==typeof t&&(t=d.parse(t)),this._data.concat(t),this._nDataBytes+=t.sigBytes},_process:function(t){var e,r=this._data,i=r.words,n=r.sigBytes,o=this.blockSize,s=n/(4*o),c=(s=t?l.ceil(s):l.max((0|s)-this._minBufferSize,0))*o,a=l.min(4*c,n);if(c){for(var h=0;h>>32-e}function Dt(t,e,r,i){var n,o=this._iv;o?(n=o.slice(0),this._iv=void 0):n=this._prevBlock,i.encryptBlock(n,0);for(var s=0;s>24&255)){var e=t>>16&255,r=t>>8&255,i=255&t;255===e?(e=0,255===r?(r=0,255===i?i=0:++i):++r):++e,t=0,t+=e<<16,t+=r<<8,t+=i}else t+=1<<24;return t}function Rt(){for(var t=this._X,e=this._C,r=0;r<8;r++)ft[r]=e[r];e[0]=e[0]+1295307597+this._b|0,e[1]=e[1]+3545052371+(e[0]>>>0>>0?1:0)|0,e[2]=e[2]+886263092+(e[1]>>>0>>0?1:0)|0,e[3]=e[3]+1295307597+(e[2]>>>0>>0?1:0)|0,e[4]=e[4]+3545052371+(e[3]>>>0>>0?1:0)|0,e[5]=e[5]+886263092+(e[4]>>>0>>0?1:0)|0,e[6]=e[6]+1295307597+(e[5]>>>0>>0?1:0)|0,e[7]=e[7]+3545052371+(e[6]>>>0>>0?1:0)|0,this._b=e[7]>>>0>>0?1:0;for(r=0;r<8;r++){var i=t[r]+e[r],n=65535&i,o=i>>>16,s=((n*n>>>17)+n*o>>>15)+o*o,c=((4294901760&i)*i|0)+((65535&i)*i|0);dt[r]=s^c}t[0]=dt[0]+(dt[7]<<16|dt[7]>>>16)+(dt[6]<<16|dt[6]>>>16)|0,t[1]=dt[1]+(dt[0]<<8|dt[0]>>>24)+dt[7]|0,t[2]=dt[2]+(dt[1]<<16|dt[1]>>>16)+(dt[0]<<16|dt[0]>>>16)|0,t[3]=dt[3]+(dt[2]<<8|dt[2]>>>24)+dt[1]|0,t[4]=dt[4]+(dt[3]<<16|dt[3]>>>16)+(dt[2]<<16|dt[2]>>>16)|0,t[5]=dt[5]+(dt[4]<<8|dt[4]>>>24)+dt[3]|0,t[6]=dt[6]+(dt[5]<<16|dt[5]>>>16)+(dt[4]<<16|dt[4]>>>16)|0,t[7]=dt[7]+(dt[6]<<8|dt[6]>>>24)+dt[5]|0}function Mt(){for(var t=this._X,e=this._C,r=0;r<8;r++)wt[r]=e[r];e[0]=e[0]+1295307597+this._b|0,e[1]=e[1]+3545052371+(e[0]>>>0>>0?1:0)|0,e[2]=e[2]+886263092+(e[1]>>>0>>0?1:0)|0,e[3]=e[3]+1295307597+(e[2]>>>0>>0?1:0)|0,e[4]=e[4]+3545052371+(e[3]>>>0>>0?1:0)|0,e[5]=e[5]+886263092+(e[4]>>>0>>0?1:0)|0,e[6]=e[6]+1295307597+(e[5]>>>0>>0?1:0)|0,e[7]=e[7]+3545052371+(e[6]>>>0>>0?1:0)|0,this._b=e[7]>>>0>>0?1:0;for(r=0;r<8;r++){var i=t[r]+e[r],n=65535&i,o=i>>>16,s=((n*n>>>17)+n*o>>>15)+o*o,c=((4294901760&i)*i|0)+((65535&i)*i|0);kt[r]=s^c}t[0]=kt[0]+(kt[7]<<16|kt[7]>>>16)+(kt[6]<<16|kt[6]>>>16)|0,t[1]=kt[1]+(kt[0]<<8|kt[0]>>>24)+kt[7]|0,t[2]=kt[2]+(kt[1]<<16|kt[1]>>>16)+(kt[0]<<16|kt[0]>>>16)|0,t[3]=kt[3]+(kt[2]<<8|kt[2]>>>24)+kt[1]|0,t[4]=kt[4]+(kt[3]<<16|kt[3]>>>16)+(kt[2]<<16|kt[2]>>>16)|0,t[5]=kt[5]+(kt[4]<<8|kt[4]>>>24)+kt[3]|0,t[6]=kt[6]+(kt[5]<<16|kt[5]>>>16)+(kt[4]<<16|kt[4]>>>16)|0,t[7]=kt[7]+(kt[6]<<8|kt[6]>>>24)+kt[5]|0}return h=bt.lib.WordArray,bt.enc.Base64={stringify:function(t){var e=t.words,r=t.sigBytes,i=this._map;t.clamp();for(var n=[],o=0;o>>2]>>>24-o%4*8&255)<<16|(e[o+1>>>2]>>>24-(o+1)%4*8&255)<<8|e[o+2>>>2]>>>24-(o+2)%4*8&255,c=0;c<4&&o+.75*c>>6*(3-c)&63));var a=i.charAt(64);if(a)for(;n.length%4;)n.push(a);return n.join("")},parse:function(t){var e=t.length,r=this._map,i=this._reverseMap;if(!i){i=this._reverseMap=[];for(var n=0;n>>6-o%4*2,a=s|c;i[n>>>2]|=a<<24-n%4*8,n++}return h.create(i,n)}(t,e,i)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},function(l){var t=bt,e=t.lib,r=e.WordArray,i=e.Hasher,n=t.algo,H=[];!function(){for(var t=0;t<64;t++)H[t]=4294967296*l.abs(l.sin(t+1))|0}();var o=n.MD5=i.extend({_doReset:function(){this._hash=new r.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(t,e){for(var r=0;r<16;r++){var i=e+r,n=t[i];t[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}var o=this._hash.words,s=t[e+0],c=t[e+1],a=t[e+2],h=t[e+3],l=t[e+4],f=t[e+5],d=t[e+6],u=t[e+7],p=t[e+8],_=t[e+9],v=t[e+10],y=t[e+11],g=t[e+12],B=t[e+13],w=t[e+14],k=t[e+15],S=o[0],m=o[1],x=o[2],b=o[3];S=z(S,m,x,b,s,7,H[0]),b=z(b,S,m,x,c,12,H[1]),x=z(x,b,S,m,a,17,H[2]),m=z(m,x,b,S,h,22,H[3]),S=z(S,m,x,b,l,7,H[4]),b=z(b,S,m,x,f,12,H[5]),x=z(x,b,S,m,d,17,H[6]),m=z(m,x,b,S,u,22,H[7]),S=z(S,m,x,b,p,7,H[8]),b=z(b,S,m,x,_,12,H[9]),x=z(x,b,S,m,v,17,H[10]),m=z(m,x,b,S,y,22,H[11]),S=z(S,m,x,b,g,7,H[12]),b=z(b,S,m,x,B,12,H[13]),x=z(x,b,S,m,w,17,H[14]),S=A(S,m=z(m,x,b,S,k,22,H[15]),x,b,c,5,H[16]),b=A(b,S,m,x,d,9,H[17]),x=A(x,b,S,m,y,14,H[18]),m=A(m,x,b,S,s,20,H[19]),S=A(S,m,x,b,f,5,H[20]),b=A(b,S,m,x,v,9,H[21]),x=A(x,b,S,m,k,14,H[22]),m=A(m,x,b,S,l,20,H[23]),S=A(S,m,x,b,_,5,H[24]),b=A(b,S,m,x,w,9,H[25]),x=A(x,b,S,m,h,14,H[26]),m=A(m,x,b,S,p,20,H[27]),S=A(S,m,x,b,B,5,H[28]),b=A(b,S,m,x,a,9,H[29]),x=A(x,b,S,m,u,14,H[30]),S=C(S,m=A(m,x,b,S,g,20,H[31]),x,b,f,4,H[32]),b=C(b,S,m,x,p,11,H[33]),x=C(x,b,S,m,y,16,H[34]),m=C(m,x,b,S,w,23,H[35]),S=C(S,m,x,b,c,4,H[36]),b=C(b,S,m,x,l,11,H[37]),x=C(x,b,S,m,u,16,H[38]),m=C(m,x,b,S,v,23,H[39]),S=C(S,m,x,b,B,4,H[40]),b=C(b,S,m,x,s,11,H[41]),x=C(x,b,S,m,h,16,H[42]),m=C(m,x,b,S,d,23,H[43]),S=C(S,m,x,b,_,4,H[44]),b=C(b,S,m,x,g,11,H[45]),x=C(x,b,S,m,k,16,H[46]),S=D(S,m=C(m,x,b,S,a,23,H[47]),x,b,s,6,H[48]),b=D(b,S,m,x,u,10,H[49]),x=D(x,b,S,m,w,15,H[50]),m=D(m,x,b,S,f,21,H[51]),S=D(S,m,x,b,g,6,H[52]),b=D(b,S,m,x,h,10,H[53]),x=D(x,b,S,m,v,15,H[54]),m=D(m,x,b,S,c,21,H[55]),S=D(S,m,x,b,p,6,H[56]),b=D(b,S,m,x,k,10,H[57]),x=D(x,b,S,m,d,15,H[58]),m=D(m,x,b,S,B,21,H[59]),S=D(S,m,x,b,l,6,H[60]),b=D(b,S,m,x,y,10,H[61]),x=D(x,b,S,m,a,15,H[62]),m=D(m,x,b,S,_,21,H[63]),o[0]=o[0]+S|0,o[1]=o[1]+m|0,o[2]=o[2]+x|0,o[3]=o[3]+b|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32;var n=l.floor(r/4294967296),o=r;e[15+(64+i>>>9<<4)]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8),e[14+(64+i>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),t.sigBytes=4*(e.length+1),this._process();for(var s=this._hash,c=s.words,a=0;a<4;a++){var h=c[a];c[a]=16711935&(h<<8|h>>>24)|4278255360&(h<<24|h>>>8)}return s},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}});function z(t,e,r,i,n,o,s){var c=t+(e&r|~e&i)+n+s;return(c<>>32-o)+e}function A(t,e,r,i,n,o,s){var c=t+(e&i|r&~i)+n+s;return(c<>>32-o)+e}function C(t,e,r,i,n,o,s){var c=t+(e^r^i)+n+s;return(c<>>32-o)+e}function D(t,e,r,i,n,o,s){var c=t+(r^(e|~i))+n+s;return(c<>>32-o)+e}t.MD5=i._createHelper(o),t.HmacMD5=i._createHmacHelper(o)}(Math),e=(t=bt).lib,r=e.WordArray,i=e.Hasher,n=t.algo,f=[],o=n.SHA1=i.extend({_doReset:function(){this._hash=new r.init([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],a=0;a<80;a++){if(a<16)f[a]=0|t[e+a];else{var h=f[a-3]^f[a-8]^f[a-14]^f[a-16];f[a]=h<<1|h>>>31}var l=(i<<5|i>>>27)+c+f[a];l+=a<20?1518500249+(n&o|~n&s):a<40?1859775393+(n^o^s):a<60?(n&o|n&s|o&s)-1894007588:(n^o^s)-899497514,c=s,s=o,o=n<<30|n>>>2,n=i,i=l}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+o|0,r[3]=r[3]+s|0,r[4]=r[4]+c|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=Math.floor(r/4294967296),e[15+(64+i>>>9<<4)]=r,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}}),t.SHA1=i._createHelper(o),t.HmacSHA1=i._createHmacHelper(o),function(n){var t=bt,e=t.lib,r=e.WordArray,i=e.Hasher,o=t.algo,s=[],B=[];!function(){function t(t){for(var e=n.sqrt(t),r=2;r<=e;r++)if(!(t%r))return;return 1}function e(t){return 4294967296*(t-(0|t))|0}for(var r=2,i=0;i<64;)t(r)&&(i<8&&(s[i]=e(n.pow(r,.5))),B[i]=e(n.pow(r,1/3)),i++),r++}();var w=[],c=o.SHA256=i.extend({_doReset:function(){this._hash=new r.init(s.slice(0))},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],a=r[5],h=r[6],l=r[7],f=0;f<64;f++){if(f<16)w[f]=0|t[e+f];else{var d=w[f-15],u=(d<<25|d>>>7)^(d<<14|d>>>18)^d>>>3,p=w[f-2],_=(p<<15|p>>>17)^(p<<13|p>>>19)^p>>>10;w[f]=u+w[f-7]+_+w[f-16]}var v=i&n^i&o^n&o,y=(i<<30|i>>>2)^(i<<19|i>>>13)^(i<<10|i>>>22),g=l+((c<<26|c>>>6)^(c<<21|c>>>11)^(c<<7|c>>>25))+(c&a^~c&h)+B[f]+w[f];l=h,h=a,a=c,c=s+g|0,s=o,o=n,n=i,i=g+(y+v)|0}r[0]=r[0]+i|0,r[1]=r[1]+n|0,r[2]=r[2]+o|0,r[3]=r[3]+s|0,r[4]=r[4]+c|0,r[5]=r[5]+a|0,r[6]=r[6]+h|0,r[7]=r[7]+l|0},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=n.floor(r/4294967296),e[15+(64+i>>>9<<4)]=r,t.sigBytes=4*e.length,this._process(),this._hash},clone:function(){var t=i.clone.call(this);return t._hash=this._hash.clone(),t}});t.SHA256=i._createHelper(c),t.HmacSHA256=i._createHmacHelper(c)}(Math),function(){var n=bt.lib.WordArray,t=bt.enc;t.Utf16=t.Utf16BE={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>16-n%4*8&65535;i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>1]|=t.charCodeAt(i)<<16-i%2*16;return n.create(r,2*e)}};function s(t){return t<<8&4278255360|t>>>8&16711935}t.Utf16LE={stringify:function(t){for(var e=t.words,r=t.sigBytes,i=[],n=0;n>>2]>>>16-n%4*8&65535);i.push(String.fromCharCode(o))}return i.join("")},parse:function(t){for(var e=t.length,r=[],i=0;i>>1]|=s(t.charCodeAt(i)<<16-i%2*16);return n.create(r,2*e)}}}(),function(){if("function"==typeof ArrayBuffer){var t=bt.lib.WordArray,n=t.init;(t.init=function(t){if(t instanceof ArrayBuffer&&(t=new Uint8Array(t)),(t instanceof Int8Array||"undefined"!=typeof Uint8ClampedArray&&t instanceof Uint8ClampedArray||t instanceof Int16Array||t instanceof Uint16Array||t instanceof Int32Array||t instanceof Uint32Array||t instanceof Float32Array||t instanceof Float64Array)&&(t=new Uint8Array(t.buffer,t.byteOffset,t.byteLength)),t instanceof Uint8Array){for(var e=t.byteLength,r=[],i=0;i>>2]|=t[i]<<24-i%4*8;n.call(this,r,e)}else n.apply(this,arguments)}).prototype=t}}(),Math,c=(s=bt).lib,a=c.WordArray,l=c.Hasher,d=s.algo,m=a.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),x=a.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),b=a.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),H=a.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),z=a.create([0,1518500249,1859775393,2400959708,2840853838]),A=a.create([1352829926,1548603684,1836072691,2053994217,0]),u=d.RIPEMD160=l.extend({_doReset:function(){this._hash=a.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,e){for(var r=0;r<16;r++){var i=e+r,n=t[i];t[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}var o,s,c,a,h,l,f,d,u,p,_,v=this._hash.words,y=z.words,g=A.words,B=m.words,w=x.words,k=b.words,S=H.words;l=o=v[0],f=s=v[1],d=c=v[2],u=a=v[3],p=h=v[4];for(r=0;r<80;r+=1)_=o+t[e+B[r]]|0,_+=r<16?mt(s,c,a)+y[0]:r<32?xt(s,c,a)+y[1]:r<48?Ht(s,c,a)+y[2]:r<64?zt(s,c,a)+y[3]:At(s,c,a)+y[4],_=(_=Ct(_|=0,k[r]))+h|0,o=h,h=a,a=Ct(c,10),c=s,s=_,_=l+t[e+w[r]]|0,_+=r<16?At(f,d,u)+g[0]:r<32?zt(f,d,u)+g[1]:r<48?Ht(f,d,u)+g[2]:r<64?xt(f,d,u)+g[3]:mt(f,d,u)+g[4],_=(_=Ct(_|=0,S[r]))+p|0,l=p,p=u,u=Ct(d,10),d=f,f=_;_=v[1]+c+u|0,v[1]=v[2]+a+p|0,v[2]=v[3]+h+l|0,v[3]=v[4]+o+f|0,v[4]=v[0]+s+d|0,v[0]=_},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(e.length+1),this._process();for(var n=this._hash,o=n.words,s=0;s<5;s++){var c=o[s];o[s]=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8)}return n},clone:function(){var t=l.clone.call(this);return t._hash=this._hash.clone(),t}}),s.RIPEMD160=l._createHelper(u),s.HmacRIPEMD160=l._createHmacHelper(u),p=bt.lib.Base,_=bt.enc.Utf8,bt.algo.HMAC=p.extend({init:function(t,e){t=this._hasher=new t.init,"string"==typeof e&&(e=_.parse(e));var r=t.blockSize,i=4*r;e.sigBytes>i&&(e=t.finalize(e)),e.clamp();for(var n=this._oKey=e.clone(),o=this._iKey=e.clone(),s=n.words,c=o.words,a=0;a>>24)|4278255360&(o<<24|o>>>8),s=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),(x=r[n]).high^=s,x.low^=o}for(var c=0;c<24;c++){for(var a=0;a<5;a++){for(var h=0,l=0,f=0;f<5;f++){h^=(x=r[a+5*f]).high,l^=x.low}var d=R[a];d.high=h,d.low=l}for(a=0;a<5;a++){var u=R[(a+4)%5],p=R[(a+1)%5],_=p.high,v=p.low;for(h=u.high^(_<<1|v>>>31),l=u.low^(v<<1|_>>>31),f=0;f<5;f++){(x=r[a+5*f]).high^=h,x.low^=l}}for(var y=1;y<25;y++){var g=(x=r[y]).high,B=x.low,w=C[y];l=w<32?(h=g<>>32-w,B<>>32-w):(h=B<>>64-w,g<>>64-w);var k=R[D[y]];k.high=h,k.low=l}var S=R[0],m=r[0];S.high=m.high,S.low=m.low;for(a=0;a<5;a++)for(f=0;f<5;f++){var x=r[y=a+5*f],b=R[y],H=R[(a+1)%5+5*f],z=R[(a+2)%5+5*f];x.high=b.high^~H.high&z.high,x.low=b.low^~H.low&z.low}x=r[0];var A=E[c];x.high^=A.high,x.low^=A.low}},_doFinalize:function(){var t=this._data,e=t.words,r=(this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;e[r>>>5]|=1<<24-r%32,e[(d.ceil((1+r)/i)*i>>>5)-1]|=128,t.sigBytes=4*e.length,this._process();for(var n=this._state,o=this.cfg.outputLength/8,s=o/8,c=[],a=0;a>>24)|4278255360&(l<<24|l>>>8),f=16711935&(f<<8|f>>>24)|4278255360&(f<<24|f>>>8),c.push(f),c.push(l)}return new u.init(c,o)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),r=0;r<25;r++)e[r]=e[r].clone();return t}});t.SHA3=i._createHelper(n),t.HmacSHA3=i._createHmacHelper(n)}(Math),function(){var t=bt,e=t.lib.Hasher,r=t.x64,i=r.Word,n=r.WordArray,o=t.algo;function s(){return i.create.apply(i,arguments)}var mt=[s(1116352408,3609767458),s(1899447441,602891725),s(3049323471,3964484399),s(3921009573,2173295548),s(961987163,4081628472),s(1508970993,3053834265),s(2453635748,2937671579),s(2870763221,3664609560),s(3624381080,2734883394),s(310598401,1164996542),s(607225278,1323610764),s(1426881987,3590304994),s(1925078388,4068182383),s(2162078206,991336113),s(2614888103,633803317),s(3248222580,3479774868),s(3835390401,2666613458),s(4022224774,944711139),s(264347078,2341262773),s(604807628,2007800933),s(770255983,1495990901),s(1249150122,1856431235),s(1555081692,3175218132),s(1996064986,2198950837),s(2554220882,3999719339),s(2821834349,766784016),s(2952996808,2566594879),s(3210313671,3203337956),s(3336571891,1034457026),s(3584528711,2466948901),s(113926993,3758326383),s(338241895,168717936),s(666307205,1188179964),s(773529912,1546045734),s(1294757372,1522805485),s(1396182291,2643833823),s(1695183700,2343527390),s(1986661051,1014477480),s(2177026350,1206759142),s(2456956037,344077627),s(2730485921,1290863460),s(2820302411,3158454273),s(3259730800,3505952657),s(3345764771,106217008),s(3516065817,3606008344),s(3600352804,1432725776),s(4094571909,1467031594),s(275423344,851169720),s(430227734,3100823752),s(506948616,1363258195),s(659060556,3750685593),s(883997877,3785050280),s(958139571,3318307427),s(1322822218,3812723403),s(1537002063,2003034995),s(1747873779,3602036899),s(1955562222,1575990012),s(2024104815,1125592928),s(2227730452,2716904306),s(2361852424,442776044),s(2428436474,593698344),s(2756734187,3733110249),s(3204031479,2999351573),s(3329325298,3815920427),s(3391569614,3928383900),s(3515267271,566280711),s(3940187606,3454069534),s(4118630271,4000239992),s(116418474,1914138554),s(174292421,2731055270),s(289380356,3203993006),s(460393269,320620315),s(685471733,587496836),s(852142971,1086792851),s(1017036298,365543100),s(1126000580,2618297676),s(1288033470,3409855158),s(1501505948,4234509866),s(1607167915,987167468),s(1816402316,1246189591)],xt=[];!function(){for(var t=0;t<80;t++)xt[t]=s()}();var c=o.SHA512=e.extend({_doReset:function(){this._hash=new n.init([new i.init(1779033703,4089235720),new i.init(3144134277,2227873595),new i.init(1013904242,4271175723),new i.init(2773480762,1595750129),new i.init(1359893119,2917565137),new i.init(2600822924,725511199),new i.init(528734635,4215389547),new i.init(1541459225,327033209)])},_doProcessBlock:function(t,e){for(var r=this._hash.words,i=r[0],n=r[1],o=r[2],s=r[3],c=r[4],a=r[5],h=r[6],l=r[7],f=i.high,d=i.low,u=n.high,p=n.low,_=o.high,v=o.low,y=s.high,g=s.low,B=c.high,w=c.low,k=a.high,S=a.low,m=h.high,x=h.low,b=l.high,H=l.low,z=f,A=d,C=u,D=p,E=_,R=v,M=y,F=g,P=B,W=w,O=k,I=S,U=m,K=x,X=b,L=H,j=0;j<80;j++){var N,T,q=xt[j];if(j<16)T=q.high=0|t[e+2*j],N=q.low=0|t[e+2*j+1];else{var Z=xt[j-15],V=Z.high,G=Z.low,J=(V>>>1|G<<31)^(V>>>8|G<<24)^V>>>7,$=(G>>>1|V<<31)^(G>>>8|V<<24)^(G>>>7|V<<25),Q=xt[j-2],Y=Q.high,tt=Q.low,et=(Y>>>19|tt<<13)^(Y<<3|tt>>>29)^Y>>>6,rt=(tt>>>19|Y<<13)^(tt<<3|Y>>>29)^(tt>>>6|Y<<26),it=xt[j-7],nt=it.high,ot=it.low,st=xt[j-16],ct=st.high,at=st.low;T=(T=(T=J+nt+((N=$+ot)>>>0<$>>>0?1:0))+et+((N+=rt)>>>0>>0?1:0))+ct+((N+=at)>>>0>>0?1:0),q.high=T,q.low=N}var ht,lt=P&O^~P&U,ft=W&I^~W&K,dt=z&C^z&E^C&E,ut=A&D^A&R^D&R,pt=(z>>>28|A<<4)^(z<<30|A>>>2)^(z<<25|A>>>7),_t=(A>>>28|z<<4)^(A<<30|z>>>2)^(A<<25|z>>>7),vt=(P>>>14|W<<18)^(P>>>18|W<<14)^(P<<23|W>>>9),yt=(W>>>14|P<<18)^(W>>>18|P<<14)^(W<<23|P>>>9),gt=mt[j],Bt=gt.high,wt=gt.low,kt=X+vt+((ht=L+yt)>>>0>>0?1:0),St=_t+ut;X=U,L=K,U=O,K=I,O=P,I=W,P=M+(kt=(kt=(kt=kt+lt+((ht=ht+ft)>>>0>>0?1:0))+Bt+((ht=ht+wt)>>>0>>0?1:0))+T+((ht=ht+N)>>>0>>0?1:0))+((W=F+ht|0)>>>0>>0?1:0)|0,M=E,F=R,E=C,R=D,C=z,D=A,z=kt+(pt+dt+(St>>>0<_t>>>0?1:0))+((A=ht+St|0)>>>0>>0?1:0)|0}d=i.low=d+A,i.high=f+z+(d>>>0>>0?1:0),p=n.low=p+D,n.high=u+C+(p>>>0>>0?1:0),v=o.low=v+R,o.high=_+E+(v>>>0>>0?1:0),g=s.low=g+F,s.high=y+M+(g>>>0>>0?1:0),w=c.low=w+W,c.high=B+P+(w>>>0>>0?1:0),S=a.low=S+I,a.high=k+O+(S>>>0>>0?1:0),x=h.low=x+K,h.high=m+U+(x>>>0>>0?1:0),H=l.low=H+L,l.high=b+X+(H>>>0>>0?1:0)},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[30+(128+i>>>10<<5)]=Math.floor(r/4294967296),e[31+(128+i>>>10<<5)]=r,t.sigBytes=4*e.length,this._process(),this._hash.toX32()},clone:function(){var t=e.clone.call(this);return t._hash=this._hash.clone(),t},blockSize:32});t.SHA512=e._createHelper(c),t.HmacSHA512=e._createHmacHelper(c)}(),Z=(q=bt).x64,V=Z.Word,G=Z.WordArray,J=q.algo,$=J.SHA512,Q=J.SHA384=$.extend({_doReset:function(){this._hash=new G.init([new V.init(3418070365,3238371032),new V.init(1654270250,914150663),new V.init(2438529370,812702999),new V.init(355462360,4144912697),new V.init(1731405415,4290775857),new V.init(2394180231,1750603025),new V.init(3675008525,1694076839),new V.init(1203062813,3204075428)])},_doFinalize:function(){var t=$._doFinalize.call(this);return t.sigBytes-=16,t}}),q.SHA384=$._createHelper(Q),q.HmacSHA384=$._createHmacHelper(Q),bt.lib.Cipher||function(){var t=bt,e=t.lib,r=e.Base,a=e.WordArray,i=e.BufferedBlockAlgorithm,n=t.enc,o=(n.Utf8,n.Base64),s=t.algo.EvpKDF,c=e.Cipher=i.extend({cfg:r.extend(),createEncryptor:function(t,e){return this.create(this._ENC_XFORM_MODE,t,e)},createDecryptor:function(t,e){return this.create(this._DEC_XFORM_MODE,t,e)},init:function(t,e,r){this.cfg=this.cfg.extend(r),this._xformMode=t,this._key=e,this.reset()},reset:function(){i.reset.call(this),this._doReset()},process:function(t){return this._append(t),this._process()},finalize:function(t){return t&&this._append(t),this._doFinalize()},keySize:4,ivSize:4,_ENC_XFORM_MODE:1,_DEC_XFORM_MODE:2,_createHelper:function(i){return{encrypt:function(t,e,r){return h(e).encrypt(i,t,e,r)},decrypt:function(t,e,r){return h(e).decrypt(i,t,e,r)}}}});function h(t){return"string"==typeof t?w:g}e.StreamCipher=c.extend({_doFinalize:function(){return this._process(!0)},blockSize:1});var l,f=t.mode={},d=e.BlockCipherMode=r.extend({createEncryptor:function(t,e){return this.Encryptor.create(t,e)},createDecryptor:function(t,e){return this.Decryptor.create(t,e)},init:function(t,e){this._cipher=t,this._iv=e}}),u=f.CBC=((l=d.extend()).Encryptor=l.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize;p.call(this,t,e,i),r.encryptBlock(t,e),this._prevBlock=t.slice(e,e+i)}}),l.Decryptor=l.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=t.slice(e,e+i);r.decryptBlock(t,e),p.call(this,t,e,i),this._prevBlock=n}}),l);function p(t,e,r){var i,n=this._iv;n?(i=n,this._iv=void 0):i=this._prevBlock;for(var o=0;o>>2];t.sigBytes-=e}},v=(e.BlockCipher=c.extend({cfg:c.cfg.extend({mode:u,padding:_}),reset:function(){var t;c.reset.call(this);var e=this.cfg,r=e.iv,i=e.mode;this._xformMode==this._ENC_XFORM_MODE?t=i.createEncryptor:(t=i.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==t?this._mode.init(this,r&&r.words):(this._mode=t.call(i,this,r&&r.words),this._mode.__creator=t)},_doProcessBlock:function(t,e){this._mode.processBlock(t,e)},_doFinalize:function(){var t,e=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(e.pad(this._data,this.blockSize),t=this._process(!0)):(t=this._process(!0),e.unpad(t)),t},blockSize:4}),e.CipherParams=r.extend({init:function(t){this.mixIn(t)},toString:function(t){return(t||this.formatter).stringify(this)}})),y=(t.format={}).OpenSSL={stringify:function(t){var e=t.ciphertext,r=t.salt;return(r?a.create([1398893684,1701076831]).concat(r).concat(e):e).toString(o)},parse:function(t){var e,r=o.parse(t),i=r.words;return 1398893684==i[0]&&1701076831==i[1]&&(e=a.create(i.slice(2,4)),i.splice(0,4),r.sigBytes-=16),v.create({ciphertext:r,salt:e})}},g=e.SerializableCipher=r.extend({cfg:r.extend({format:y}),encrypt:function(t,e,r,i){i=this.cfg.extend(i);var n=t.createEncryptor(r,i),o=n.finalize(e),s=n.cfg;return v.create({ciphertext:o,key:r,iv:s.iv,algorithm:t,mode:s.mode,padding:s.padding,blockSize:t.blockSize,formatter:i.format})},decrypt:function(t,e,r,i){return i=this.cfg.extend(i),e=this._parse(e,i.format),t.createDecryptor(r,i).finalize(e.ciphertext)},_parse:function(t,e){return"string"==typeof t?e.parse(t,this):t}}),B=(t.kdf={}).OpenSSL={execute:function(t,e,r,i){i=i||a.random(8);var n=s.create({keySize:e+r}).compute(t,i),o=a.create(n.words.slice(e),4*r);return n.sigBytes=4*e,v.create({key:n,iv:o,salt:i})}},w=e.PasswordBasedCipher=g.extend({cfg:g.cfg.extend({kdf:B}),encrypt:function(t,e,r,i){var n=(i=this.cfg.extend(i)).kdf.execute(r,t.keySize,t.ivSize);i.iv=n.iv;var o=g.encrypt.call(this,t,e,n.key,i);return o.mixIn(n),o},decrypt:function(t,e,r,i){i=this.cfg.extend(i),e=this._parse(e,i.format);var n=i.kdf.execute(r,t.keySize,t.ivSize,e.salt);return i.iv=n.iv,g.decrypt.call(this,t,e,n.key,i)}})}(),bt.mode.CFB=((Y=bt.lib.BlockCipherMode.extend()).Encryptor=Y.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize;Dt.call(this,t,e,i,r),this._prevBlock=t.slice(e,e+i)}}),Y.Decryptor=Y.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=t.slice(e,e+i);Dt.call(this,t,e,i,r),this._prevBlock=n}}),Y),bt.mode.ECB=((tt=bt.lib.BlockCipherMode.extend()).Encryptor=tt.extend({processBlock:function(t,e){this._cipher.encryptBlock(t,e)}}),tt.Decryptor=tt.extend({processBlock:function(t,e){this._cipher.decryptBlock(t,e)}}),tt),bt.pad.AnsiX923={pad:function(t,e){var r=t.sigBytes,i=4*e,n=i-r%i,o=r+n-1;t.clamp(),t.words[o>>>2]|=n<<24-o%4*8,t.sigBytes+=n},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},bt.pad.Iso10126={pad:function(t,e){var r=4*e,i=r-t.sigBytes%r;t.concat(bt.lib.WordArray.random(i-1)).concat(bt.lib.WordArray.create([i<<24],1))},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},bt.pad.Iso97971={pad:function(t,e){t.concat(bt.lib.WordArray.create([2147483648],1)),bt.pad.ZeroPadding.pad(t,e)},unpad:function(t){bt.pad.ZeroPadding.unpad(t),t.sigBytes--}},bt.mode.OFB=(et=bt.lib.BlockCipherMode.extend(),rt=et.Encryptor=et.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=this._iv,o=this._keystream;n&&(o=this._keystream=n.slice(0),this._iv=void 0),r.encryptBlock(o,0);for(var s=0;s>>8^255&n^99,h[r]=n;var o=t[l[n]=r],s=t[o],c=t[s],a=257*t[n]^16843008*n;f[r]=a<<24|a>>>8,d[r]=a<<16|a>>>16,u[r]=a<<8|a>>>24,p[r]=a;a=16843009*c^65537*s^257*o^16843008*r;_[n]=a<<24|a>>>8,v[n]=a<<16|a>>>16,y[n]=a<<8|a>>>24,g[n]=a,r?(r=o^t[t[t[c^o]]],i^=t[t[i]]):r=i=1}}();var B=[0,1,2,4,8,16,32,64,128,27,54],i=r.AES=e.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var t=this._keyPriorReset=this._key,e=t.words,r=t.sigBytes/4,i=4*(1+(this._nRounds=6+r)),n=this._keySchedule=[],o=0;o>>24]<<24|h[a>>>16&255]<<16|h[a>>>8&255]<<8|h[255&a]):(a=h[(a=a<<8|a>>>24)>>>24]<<24|h[a>>>16&255]<<16|h[a>>>8&255]<<8|h[255&a],a^=B[o/r|0]<<24),n[o]=n[o-r]^a);for(var s=this._invKeySchedule=[],c=0;c>>24]]^v[h[a>>>16&255]]^y[h[a>>>8&255]]^g[h[255&a]]}}},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._keySchedule,f,d,u,p,h)},decryptBlock:function(t,e){var r=t[e+1];t[e+1]=t[e+3],t[e+3]=r,this._doCryptBlock(t,e,this._invKeySchedule,_,v,y,g,l);r=t[e+1];t[e+1]=t[e+3],t[e+3]=r},_doCryptBlock:function(t,e,r,i,n,o,s,c){for(var a=this._nRounds,h=t[e]^r[0],l=t[e+1]^r[1],f=t[e+2]^r[2],d=t[e+3]^r[3],u=4,p=1;p>>24]^n[l>>>16&255]^o[f>>>8&255]^s[255&d]^r[u++],v=i[l>>>24]^n[f>>>16&255]^o[d>>>8&255]^s[255&h]^r[u++],y=i[f>>>24]^n[d>>>16&255]^o[h>>>8&255]^s[255&l]^r[u++],g=i[d>>>24]^n[h>>>16&255]^o[l>>>8&255]^s[255&f]^r[u++];h=_,l=v,f=y,d=g}_=(c[h>>>24]<<24|c[l>>>16&255]<<16|c[f>>>8&255]<<8|c[255&d])^r[u++],v=(c[l>>>24]<<24|c[f>>>16&255]<<16|c[d>>>8&255]<<8|c[255&h])^r[u++],y=(c[f>>>24]<<24|c[d>>>16&255]<<16|c[h>>>8&255]<<8|c[255&l])^r[u++],g=(c[d>>>24]<<24|c[h>>>16&255]<<16|c[l>>>8&255]<<8|c[255&f])^r[u++];t[e]=_,t[e+1]=v,t[e+2]=y,t[e+3]=g},keySize:8});t.AES=e._createHelper(i)}(),function(){var t=bt,e=t.lib,n=e.WordArray,r=e.BlockCipher,i=t.algo,h=[57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4],l=[14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32],f=[1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28],d=[{0:8421888,268435456:32768,536870912:8421378,805306368:2,1073741824:512,1342177280:8421890,1610612736:8389122,1879048192:8388608,2147483648:514,2415919104:8389120,2684354560:33280,2952790016:8421376,3221225472:32770,3489660928:8388610,3758096384:0,4026531840:33282,134217728:0,402653184:8421890,671088640:33282,939524096:32768,1207959552:8421888,1476395008:512,1744830464:8421378,2013265920:2,2281701376:8389120,2550136832:33280,2818572288:8421376,3087007744:8389122,3355443200:8388610,3623878656:32770,3892314112:514,4160749568:8388608,1:32768,268435457:2,536870913:8421888,805306369:8388608,1073741825:8421378,1342177281:33280,1610612737:512,1879048193:8389122,2147483649:8421890,2415919105:8421376,2684354561:8388610,2952790017:33282,3221225473:514,3489660929:8389120,3758096385:32770,4026531841:0,134217729:8421890,402653185:8421376,671088641:8388608,939524097:512,1207959553:32768,1476395009:8388610,1744830465:2,2013265921:33282,2281701377:32770,2550136833:8389122,2818572289:514,3087007745:8421888,3355443201:8389120,3623878657:0,3892314113:33280,4160749569:8421378},{0:1074282512,16777216:16384,33554432:524288,50331648:1074266128,67108864:1073741840,83886080:1074282496,100663296:1073758208,117440512:16,134217728:540672,150994944:1073758224,167772160:1073741824,184549376:540688,201326592:524304,218103808:0,234881024:16400,251658240:1074266112,8388608:1073758208,25165824:540688,41943040:16,58720256:1073758224,75497472:1074282512,92274688:1073741824,109051904:524288,125829120:1074266128,142606336:524304,159383552:0,176160768:16384,192937984:1074266112,209715200:1073741840,226492416:540672,243269632:1074282496,260046848:16400,268435456:0,285212672:1074266128,301989888:1073758224,318767104:1074282496,335544320:1074266112,352321536:16,369098752:540688,385875968:16384,402653184:16400,419430400:524288,436207616:524304,452984832:1073741840,469762048:540672,486539264:1073758208,503316480:1073741824,520093696:1074282512,276824064:540688,293601280:524288,310378496:1074266112,327155712:16384,343932928:1073758208,360710144:1074282512,377487360:16,394264576:1073741824,411041792:1074282496,427819008:1073741840,444596224:1073758224,461373440:524304,478150656:0,494927872:16400,511705088:1074266128,528482304:540672},{0:260,1048576:0,2097152:67109120,3145728:65796,4194304:65540,5242880:67108868,6291456:67174660,7340032:67174400,8388608:67108864,9437184:67174656,10485760:65792,11534336:67174404,12582912:67109124,13631488:65536,14680064:4,15728640:256,524288:67174656,1572864:67174404,2621440:0,3670016:67109120,4718592:67108868,5767168:65536,6815744:65540,7864320:260,8912896:4,9961472:256,11010048:67174400,12058624:65796,13107200:65792,14155776:67109124,15204352:67174660,16252928:67108864,16777216:67174656,17825792:65540,18874368:65536,19922944:67109120,20971520:256,22020096:67174660,23068672:67108868,24117248:0,25165824:67109124,26214400:67108864,27262976:4,28311552:65792,29360128:67174400,30408704:260,31457280:65796,32505856:67174404,17301504:67108864,18350080:260,19398656:67174656,20447232:0,21495808:65540,22544384:67109120,23592960:256,24641536:67174404,25690112:65536,26738688:67174660,27787264:65796,28835840:67108868,29884416:67109124,30932992:67174400,31981568:4,33030144:65792},{0:2151682048,65536:2147487808,131072:4198464,196608:2151677952,262144:0,327680:4198400,393216:2147483712,458752:4194368,524288:2147483648,589824:4194304,655360:64,720896:2147487744,786432:2151678016,851968:4160,917504:4096,983040:2151682112,32768:2147487808,98304:64,163840:2151678016,229376:2147487744,294912:4198400,360448:2151682112,425984:0,491520:2151677952,557056:4096,622592:2151682048,688128:4194304,753664:4160,819200:2147483648,884736:4194368,950272:4198464,1015808:2147483712,1048576:4194368,1114112:4198400,1179648:2147483712,1245184:0,1310720:4160,1376256:2151678016,1441792:2151682048,1507328:2147487808,1572864:2151682112,1638400:2147483648,1703936:2151677952,1769472:4198464,1835008:2147487744,1900544:4194304,1966080:64,2031616:4096,1081344:2151677952,1146880:2151682112,1212416:0,1277952:4198400,1343488:4194368,1409024:2147483648,1474560:2147487808,1540096:64,1605632:2147483712,1671168:4096,1736704:2147487744,1802240:2151678016,1867776:4160,1933312:2151682048,1998848:4194304,2064384:4198464},{0:128,4096:17039360,8192:262144,12288:536870912,16384:537133184,20480:16777344,24576:553648256,28672:262272,32768:16777216,36864:537133056,40960:536871040,45056:553910400,49152:553910272,53248:0,57344:17039488,61440:553648128,2048:17039488,6144:553648256,10240:128,14336:17039360,18432:262144,22528:537133184,26624:553910272,30720:536870912,34816:537133056,38912:0,43008:553910400,47104:16777344,51200:536871040,55296:553648128,59392:16777216,63488:262272,65536:262144,69632:128,73728:536870912,77824:553648256,81920:16777344,86016:553910272,90112:537133184,94208:16777216,98304:553910400,102400:553648128,106496:17039360,110592:537133056,114688:262272,118784:536871040,122880:0,126976:17039488,67584:553648256,71680:16777216,75776:17039360,79872:537133184,83968:536870912,88064:17039488,92160:128,96256:553910272,100352:262272,104448:553910400,108544:0,112640:553648128,116736:16777344,120832:262144,124928:537133056,129024:536871040},{0:268435464,256:8192,512:270532608,768:270540808,1024:268443648,1280:2097152,1536:2097160,1792:268435456,2048:0,2304:268443656,2560:2105344,2816:8,3072:270532616,3328:2105352,3584:8200,3840:270540800,128:270532608,384:270540808,640:8,896:2097152,1152:2105352,1408:268435464,1664:268443648,1920:8200,2176:2097160,2432:8192,2688:268443656,2944:270532616,3200:0,3456:270540800,3712:2105344,3968:268435456,4096:268443648,4352:270532616,4608:270540808,4864:8200,5120:2097152,5376:268435456,5632:268435464,5888:2105344,6144:2105352,6400:0,6656:8,6912:270532608,7168:8192,7424:268443656,7680:270540800,7936:2097160,4224:8,4480:2105344,4736:2097152,4992:268435464,5248:268443648,5504:8200,5760:270540808,6016:270532608,6272:270540800,6528:270532616,6784:8192,7040:2105352,7296:2097160,7552:0,7808:268435456,8064:268443656},{0:1048576,16:33555457,32:1024,48:1049601,64:34604033,80:0,96:1,112:34603009,128:33555456,144:1048577,160:33554433,176:34604032,192:34603008,208:1025,224:1049600,240:33554432,8:34603009,24:0,40:33555457,56:34604032,72:1048576,88:33554433,104:33554432,120:1025,136:1049601,152:33555456,168:34603008,184:1048577,200:1024,216:34604033,232:1,248:1049600,256:33554432,272:1048576,288:33555457,304:34603009,320:1048577,336:33555456,352:34604032,368:1049601,384:1025,400:34604033,416:1049600,432:1,448:0,464:34603008,480:33554433,496:1024,264:1049600,280:33555457,296:34603009,312:1,328:33554432,344:1048576,360:1025,376:34604032,392:33554433,408:34603008,424:0,440:34604033,456:1049601,472:1024,488:33555456,504:1048577},{0:134219808,1:131072,2:134217728,3:32,4:131104,5:134350880,6:134350848,7:2048,8:134348800,9:134219776,10:133120,11:134348832,12:2080,13:0,14:134217760,15:133152,2147483648:2048,2147483649:134350880,2147483650:134219808,2147483651:134217728,2147483652:134348800,2147483653:133120,2147483654:133152,2147483655:32,2147483656:134217760,2147483657:2080,2147483658:131104,2147483659:134350848,2147483660:0,2147483661:134348832,2147483662:134219776,2147483663:131072,16:133152,17:134350848,18:32,19:2048,20:134219776,21:134217760,22:134348832,23:131072,24:0,25:131104,26:134348800,27:134219808,28:134350880,29:133120,30:2080,31:134217728,2147483664:131072,2147483665:2048,2147483666:134348832,2147483667:133152,2147483668:32,2147483669:134348800,2147483670:134217728,2147483671:134219808,2147483672:134350880,2147483673:134217760,2147483674:134219776,2147483675:0,2147483676:133120,2147483677:2080,2147483678:131104,2147483679:134350848}],u=[4160749569,528482304,33030144,2064384,129024,8064,504,2147483679],o=i.DES=r.extend({_doReset:function(){for(var t=this._key.words,e=[],r=0;r<56;r++){var i=h[r]-1;e[r]=t[i>>>5]>>>31-i%32&1}for(var n=this._subKeys=[],o=0;o<16;o++){var s=n[o]=[],c=f[o];for(r=0;r<24;r++)s[r/6|0]|=e[(l[r]-1+c)%28]<<31-r%6,s[4+(r/6|0)]|=e[28+(l[r+24]-1+c)%28]<<31-r%6;s[0]=s[0]<<1|s[0]>>>31;for(r=1;r<7;r++)s[r]=s[r]>>>4*(r-1)+3;s[7]=s[7]<<5|s[7]>>>27}var a=this._invSubKeys=[];for(r=0;r<16;r++)a[r]=n[15-r]},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._subKeys)},decryptBlock:function(t,e){this._doCryptBlock(t,e,this._invSubKeys)},_doCryptBlock:function(t,e,r){this._lBlock=t[e],this._rBlock=t[e+1],p.call(this,4,252645135),p.call(this,16,65535),_.call(this,2,858993459),_.call(this,8,16711935),p.call(this,1,1431655765);for(var i=0;i<16;i++){for(var n=r[i],o=this._lBlock,s=this._rBlock,c=0,a=0;a<8;a++)c|=d[a][((s^n[a])&u[a])>>>0];this._lBlock=s,this._rBlock=o^c}var h=this._lBlock;this._lBlock=this._rBlock,this._rBlock=h,p.call(this,1,1431655765),_.call(this,8,16711935),_.call(this,2,858993459),p.call(this,16,65535),p.call(this,4,252645135),t[e]=this._lBlock,t[e+1]=this._rBlock},keySize:2,ivSize:2,blockSize:2});function p(t,e){var r=(this._lBlock>>>t^this._rBlock)&e;this._rBlock^=r,this._lBlock^=r<>>t^this._lBlock)&e;this._lBlock^=r,this._rBlock^=r<192.");var e=t.slice(0,2),r=t.length<4?t.slice(0,2):t.slice(2,4),i=t.length<6?t.slice(0,2):t.slice(4,6);this._des1=o.createEncryptor(n.create(e)),this._des2=o.createEncryptor(n.create(r)),this._des3=o.createEncryptor(n.create(i))},encryptBlock:function(t,e){this._des1.encryptBlock(t,e),this._des2.decryptBlock(t,e),this._des3.encryptBlock(t,e)},decryptBlock:function(t,e){this._des3.decryptBlock(t,e),this._des2.encryptBlock(t,e),this._des1.decryptBlock(t,e)},keySize:6,ivSize:2,blockSize:2});t.TripleDES=r._createHelper(s)}(),function(){var t=bt,e=t.lib.StreamCipher,r=t.algo,i=r.RC4=e.extend({_doReset:function(){for(var t=this._key,e=t.words,r=t.sigBytes,i=this._S=[],n=0;n<256;n++)i[n]=n;n=0;for(var o=0;n<256;n++){var s=n%r,c=e[s>>>2]>>>24-s%4*8&255;o=(o+i[n]+c)%256;var a=i[n];i[n]=i[o],i[o]=a}this._i=this._j=0},_doProcessBlock:function(t,e){t[e]^=n.call(this)},keySize:8,ivSize:0});function n(){for(var t=this._S,e=this._i,r=this._j,i=0,n=0;n<4;n++){r=(r+t[e=(e+1)%256])%256;var o=t[e];t[e]=t[r],t[r]=o,i|=t[(t[e]+t[r])%256]<<24-8*n}return this._i=e,this._j=r,i}t.RC4=e._createHelper(i);var o=r.RC4Drop=i.extend({cfg:i.cfg.extend({drop:192}),_doReset:function(){i._doReset.call(this);for(var t=this.cfg.drop;0>>24)|4278255360&(t[r]<<24|t[r]>>>8);var i=this._X=[t[0],t[3]<<16|t[2]>>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],n=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]];for(r=this._b=0;r<4;r++)Rt.call(this);for(r=0;r<8;r++)n[r]^=i[r+4&7];if(e){var o=e.words,s=o[0],c=o[1],a=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),h=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),l=a>>>16|4294901760&h,f=h<<16|65535&a;n[0]^=a,n[1]^=l,n[2]^=h,n[3]^=f,n[4]^=a,n[5]^=l,n[6]^=h,n[7]^=f;for(r=0;r<4;r++)Rt.call(this)}},_doProcessBlock:function(t,e){var r=this._X;Rt.call(this),lt[0]=r[0]^r[5]>>>16^r[3]<<16,lt[1]=r[2]^r[7]>>>16^r[5]<<16,lt[2]=r[4]^r[1]>>>16^r[7]<<16,lt[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)lt[i]=16711935&(lt[i]<<8|lt[i]>>>24)|4278255360&(lt[i]<<24|lt[i]>>>8),t[e+i]^=lt[i]},blockSize:4,ivSize:2}),ct.Rabbit=at._createHelper(ut),bt.mode.CTR=(pt=bt.lib.BlockCipherMode.extend(),_t=pt.Encryptor=pt.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=this._iv,o=this._counter;n&&(o=this._counter=n.slice(0),this._iv=void 0);var s=o.slice(0);r.encryptBlock(s,0),o[i-1]=o[i-1]+1|0;for(var c=0;c>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],i=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]],n=this._b=0;n<4;n++)Mt.call(this);for(n=0;n<8;n++)i[n]^=r[n+4&7];if(e){var o=e.words,s=o[0],c=o[1],a=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),h=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),l=a>>>16|4294901760&h,f=h<<16|65535&a;i[0]^=a,i[1]^=l,i[2]^=h,i[3]^=f,i[4]^=a,i[5]^=l,i[6]^=h,i[7]^=f;for(n=0;n<4;n++)Mt.call(this)}},_doProcessBlock:function(t,e){var r=this._X;Mt.call(this),Bt[0]=r[0]^r[5]>>>16^r[3]<<16,Bt[1]=r[2]^r[7]>>>16^r[5]<<16,Bt[2]=r[4]^r[1]>>>16^r[7]<<16,Bt[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)Bt[i]=16711935&(Bt[i]<<8|Bt[i]>>>24)|4278255360&(Bt[i]<<24|Bt[i]>>>8),t[e+i]^=Bt[i]},blockSize:4,ivSize:2}),vt.RabbitLegacy=yt._createHelper(St),bt.pad.ZeroPadding={pad:function(t,e){var r=4*e;t.clamp(),t.sigBytes+=r-(t.sigBytes%r||r)},unpad:function(t){var e=t.words,r=t.sigBytes-1;for(r=t.sigBytes-1;0<=r;r--)if(e[r>>>2]>>>24-r%4*8&255){t.sigBytes=r+1;break}}},bt}); '''; static String getSign(String html, String rid) { JsRuntime flutterJs = JsRuntime( memoryLimit: 4 * 1024 * 1024, maxStackSize: 64 * 1024, ); flutterJs.eval(kCryptoJs); var did = "10000000000000000000000000001501"; var time = (DateTime.now().millisecondsSinceEpoch / 1000).round(); flutterJs.eval(html); var data = flutterJs.eval("ub98484234('$rid','$did','$time')"); flutterJs.dispose(); return data; } } ================================================ FILE: simple_live_core/packages/tars_dart/.gitignore ================================================ .DS_Store .dart_tool/ .packages .pub/ .idea/ .vagrant/ .sconsign.dblite .svn/ *.swp profile DerivedData/ .generated/ *.pbxuser *.mode1v3 *.mode2v3 *.perspectivev3 !default.pbxuser !default.mode1v3 !default.mode2v3 !default.perspectivev3 xcuserdata *.moved-aside *.pyc *sync/ Icon? .tags* build/ .android/ .ios/ .flutter-plugins .flutter-plugins-dependencies # Symbolication related app.*.symbols # Obfuscation related app.*.map.json pubspec.lock tars_flutter.iml tars_flutter_android.iml .metadata ================================================ FILE: simple_live_core/packages/tars_dart/CHANGELOG.md ================================================ ## 0.1.0 - add doc ## 0.0.8 - first commit ================================================ FILE: simple_live_core/packages/tars_dart/LICENSE ================================================ BSD 3-Clause License Copyright (c) 2021, THE TARS FOUNDATION All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: simple_live_core/packages/tars_dart/README.md ================================================ # Readme Fork from https://github.dev/brooklet/TarsFlutter - 修改为dart包 - 增加tup2支持 ================================================ FILE: simple_live_core/packages/tars_dart/analysis_options.yaml ================================================ include: package:lints/recommended.yaml # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_decode_exception.dart ================================================ class TarsDecodeException extends Error { String message; TarsDecodeException(this.message); @override String toString() { return message; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_deep_copyable.dart ================================================ abstract class DeepCopyable { Object deepCopy(); } List listDeepCopy(List list) { List newList = List.filled(0, list[0], growable: true); for (var value in list) { newList.add(value is Map ? mapDeepCopy(value) : value is List ? listDeepCopy(value) : value is Set ? setDeepCopy(value) : value is DeepCopyable ? value.deepCopy() as T : value); } return newList; } Set setDeepCopy(Set s) { Set newSet = {}; for (var value in s) { newSet.add(value is Map ? mapDeepCopy(value) : value is List ? listDeepCopy(value) : value is Set ? setDeepCopy(value) : value is DeepCopyable ? value.deepCopy() as T : value); } return newSet; } Map mapDeepCopy(Map map) { Map newMap = {}; map.forEach((key, value) { newMap[key] = (value is Map ? mapDeepCopy(value) : value is List ? listDeepCopy(value) : value is Set ? setDeepCopy(value) : value is DeepCopyable ? value.deepCopy() as V : value) as V; }); return newMap; } Map> mapListDeepCopy(Map> map) { Map> newMap = >{}; map.forEach((key, value) { newMap[key] = listDeepCopy(value); }); return newMap; } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_displayer.dart ================================================ // ignore_for_file: non_constant_identifier_names import 'dart:typed_data'; import './tars_encode_exception.dart'; import './tars_struct.dart'; class TarsDisplayer { late StringBuffer sb; int _level = 0; TarsDisplayer(this.sb, {int level = 0}) { _level = level; } void ps(String? fieldName) { for (var i = 0; i < _level; ++i) { sb.write('\t'); } if (fieldName != null) { sb.write(fieldName); sb.write(': '); } } TarsDisplayer? display(dynamic value, String? fieldName) { if (value is bool) { return DisplayBool(value, fieldName); } if (value is int) { return DisplayInt(value, fieldName); } if (value is double) { return DisplayDouble(value, fieldName); } if (value is String) { return DisplayString(value, fieldName); } if (value is Uint8List) { return DisplayUint8List(value, fieldName); } if (value is List) { return DisplayArray(value, fieldName); } if (value is Map) { return DisplayMap(value, fieldName); } if (value is TarsStruct) { return DisplayTarsStruct(value, fieldName); } throw TarsEncodeException('write object error: unsupport type.'); } TarsDisplayer DisplayBool(bool b, String? fieldName) { ps(fieldName); sb.write(b ? 'T' : 'F'); sb.write('\n'); return this; } TarsDisplayer DisplayInt(int n, String? fieldName) { ps(fieldName); sb.write(n); sb.write('\n'); return this; } TarsDisplayer DisplayDouble(double n, String? fieldName) { ps(fieldName); sb.write(n); sb.write('\n'); return this; } TarsDisplayer DisplayString(String? s, String? fieldName) { ps(fieldName); if (null == s) { sb.write('null'); sb.write('\n'); } else { sb.write(s); sb.write('\n'); } return this; } TarsDisplayer DisplayUint8List(Uint8List? v, String? fieldName) { ps(fieldName); if (null == v) { sb.write('null'); sb.write('\n'); return this; } if (v.isEmpty) { sb.write(v.length); sb.write(', []'); sb.write('\n'); return this; } sb.write(v.length); sb.write(', []'); sb.write('\n'); var jd = TarsDisplayer(sb, level: _level + 1); for (var o in v) { jd.display(o, null); } display(']', null); return this; } TarsDisplayer DisplayMap(Map? m, String? fieldName) { ps(fieldName); if (null == m) { sb.write('null'); sb.write('\n'); return this; } if (m.isEmpty) { sb.write(m.length); sb.write(', {}'); sb.write('\n'); return this; } sb.write(m.length); sb.write(', {'); sb.write('\n'); var jd1 = TarsDisplayer(sb, level: _level + 1); var jd = TarsDisplayer(sb, level: _level + 2); for (var key in m.keys) { jd1.display('(', null); jd.display(key, null); jd.display(m[key], null); jd1.display(')', null); } display('}', null); return this; } TarsDisplayer DisplayArray(List? v, String? fieldName) { ps(fieldName); if (null == v) { sb.write('null'); sb.write('\n'); return this; } if (v.isEmpty) { sb.write(v.length); sb.write(', []'); sb.write('\n'); return this; } sb.write(v.length); sb.write(', ['); sb.write('\n'); var jd = TarsDisplayer(sb, level: _level + 1); for (var o in v) { jd.display(o, null); } display(']', null); return this; } TarsDisplayer DisplayList(List? v, String? fieldName) { if (null == v) { ps(fieldName); sb.write('null'); sb.write('\n'); return this; } else { for (var item in v) { display(item, fieldName); } return this; } } TarsDisplayer DisplayTarsStruct(TarsStruct? v, String? fieldName) { display('{', fieldName); if (null == v) { sb.write('\t'); sb.write('null'); } else { v.displayAsString(sb, _level + 1); } display('}', null); return this; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_encode_exception.dart ================================================ class TarsEncodeException extends Error { String message; TarsEncodeException(this.message); @override String toString() { return message; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_input_stream.dart ================================================ import 'dart:convert'; import 'dart:core'; import 'dart:typed_data'; import 'tars_struct.dart'; import 'tars_decode_exception.dart'; class HeadData { int type = 0; int tag = 0; void clear() { type = 0; tag = 0; } } class BinaryReader { Uint8List buffer; int position = 0; BinaryReader(this.buffer); int get length => buffer.length; /// 从当前流中读取下一个字节,并使流的当前位置提升 1 个字节 /// 返回下一个字节(0-255) int read() { var byte = buffer[position]; position += 1; return byte; } /// 从当前流中读取指定长度的字节整数,并使流的当前位置提升指定长度。 /// [len] 指定长度 /// len=1为int8,2为int16,4为int32,8为int64。dart中统一为int类型 /// 返回整数 int readInt(int len) { var result = 0; // if (len == 1) { // result = buffer[position]; // position += len; // return result; // } var bytes = Uint8List.fromList(buffer.getRange(position, position + len).toList()); var byteBuffer = bytes.buffer; var data = ByteData.view(byteBuffer); if (len == 1) { result = data.getUint8(0); } if (len == 2) { result = data.getInt16(0, Endian.big); } if (len == 4) { result = data.getInt32(0, Endian.big); } if (len == 8) { result = data.getInt64(0, Endian.big); } position += len; return result; } /// 从当前流中读取指定长度的字节数组,并使流的当前位置提升指定长度。 /// [len] 指定长度 /// 返回字节数组 Uint8List readBytes(int len) { var bytes = Uint8List.fromList(buffer.getRange(position, position + len).toList()); position += len; return bytes; } /// 从当前流中读取指定长度的字节浮点数,并使流的当前位置提升指定长度。 /// [len] 指定长度 /// len=4为float,8为double。dart中统一为double类型 /// 返回浮点数 double readFloat(int len) { var result = 0.0; var bytes = Uint8List.fromList(buffer.getRange(position, position + len).toList()); var byteBuffer = bytes.buffer; var data = ByteData.view(byteBuffer); if (len == 4) { result = data.getFloat32(0, Endian.big); } if (len == 8) { result = data.getFloat64(0, Endian.big); } position += len; return result; } } class TarsInputStream { late BinaryReader br; TarsInputStream(Uint8List? bytes, {int pos = 0}) { if (bytes != null) { br = BinaryReader(bytes); br.position = pos; } } void wrap(Uint8List bytes, {int pos = 0}) { br = BinaryReader(bytes); br.position = pos; } static int readBinaryReaderHead(HeadData hd, BinaryReader bb) { if (bb.position >= bb.length) { throw TarsDecodeException('read file to end'); } var b = bb.read(); hd.type = (b & 15); hd.tag = ((b & (15 << 4)) >> 4); if (hd.tag == 15) { hd.tag = bb.read(); return 2; } return 1; } int readHead(HeadData hd) { return readBinaryReaderHead(hd, br); } int peakHead(HeadData hd) { var curPos = br.position; var len = readHead(hd); br.position = curPos; return len; } void skip(int len) { br.position += len; } bool skipToTag(int tag) { try { var hd = HeadData(); while (true) { var len = peakHead(hd); if (tag <= hd.tag || hd.type == TarsStructType.STRUCT_END.index) { return tag == hd.tag; } skip(len); skipFieldWithType(hd.type); } } catch (e) { if (e is TarsDecodeException) { print(e); } print(e); } return false; } // 跳到当前结构的结束位置 void skipToStructEnd() { var hd = HeadData(); do { readHead(hd); skipFieldWithType(hd.type); } while (hd.type != TarsStructType.STRUCT_END.index); } // 跳过一个字段 void skipField() { var hd = HeadData(); readHead(hd); skipFieldWithType(hd.type); } void skipFieldWithType(int type) { var t = TarsStructType.values[type]; switch (t) { case TarsStructType.BYTE: skip(1); break; case TarsStructType.SHORT: skip(2); break; case TarsStructType.INT: skip(4); break; case TarsStructType.LONG: skip(8); break; case TarsStructType.FLOAT: skip(4); break; case TarsStructType.DOUBLE: skip(8); break; case TarsStructType.STRING1: { var len = br.read(); if (len < 0) { len += 256; } skip(len); break; } case TarsStructType.STRING4: { skip(br.readInt(4)); break; } case TarsStructType.MAP: { var size = readInt(0, true); for (var i = 0; i < size * 2; ++i) { skipField(); } break; } case TarsStructType.LIST: { var size = readInt(0, true); for (var i = 0; i < size; ++i) { skipField(); } break; } case TarsStructType.SIMPLE_LIST: { var hd = HeadData(); readHead(hd); if (hd.type != TarsStructType.BYTE.index) { throw TarsDecodeException( 'skipField with invalid type, type value: $type,${hd.type}'); } var size = readInt(0, true); skip(size); break; } case TarsStructType.STRUCT_BEGIN: skipToStructEnd(); break; case TarsStructType.STRUCT_END: case TarsStructType.ZERO_TAG: break; } } dynamic read(dynamic data, int tag, bool isRequire) { if (data is int || data == int) { data = readInt(tag, isRequire); } else if (data is double || data == double) { data = readFloat(tag, isRequire); } else if (data is bool || data == bool) { data = readBool(tag, isRequire); } else if (data is Uint8List || data == Uint8List) { data = readBytes(tag, isRequire); } else if (data is String || data == String) { data = readString(tag, isRequire); } else if (data is List || data == List) { data = readList(data, tag, isRequire); } else if (data is Map || data == Map) { data = readMap(data, tag, isRequire); } else if (data is TarsStruct || data == TarsStruct) { data = readTarsStruct(data, tag, isRequire); } else { throw TarsDecodeException('type:${data.runtimeType} not supported.'); } return data; } /// 读取整数 /// 对应Tars类型:int1、int2、int4、int8 int readInt(int tag, bool isRequire) { var n = 0; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; switch (t) { case TarsStructType.ZERO_TAG: n = 0; break; case TarsStructType.BYTE: n = br.readInt(1); break; case TarsStructType.SHORT: n = br.readInt(2); break; case TarsStructType.INT: n = br.readInt(4); break; case TarsStructType.LONG: n = br.readInt(8); break; default: throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return n; } /// 读取bool /// 对应Tars类型:int1 bool readBool(int tag, bool isRequire) { return readInt(tag, isRequire) != 0; } /// 读取单字char /// 对应Tars类型:int String readChar(int tag, bool isRequire) { var char = readInt(tag, isRequire); return String.fromCharCode(char); } /// 读取字符串 /// 对应Tars类型:string1、string4 String readString(int tag, bool isRequire) { var n = ''; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; switch (t) { case TarsStructType.STRING1: n = _readString1(); break; case TarsStructType.STRING4: n = _readString4(); break; default: throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return n; } String _readString1() { var len = 0; len = br.readInt(1); if (len < 0) { len += 256; } var ss = br.readBytes(len); return utf8.decode(ss); } String _readString4() { var len = 0; len = br.readInt(4); if (len > TarsStruct.TARS_MAX_STRING_LENGTH || len < 0) { throw TarsDecodeException('string too long: $len'); } var ss = br.readBytes(len); return utf8.decode(ss); } /// 读取浮点数 /// 对应Tars类型:double、float double readFloat(int tag, bool isRequire) { var n = 0.0; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; switch (t) { case TarsStructType.ZERO_TAG: n = 0; break; case TarsStructType.FLOAT: { n = br.readFloat(4); } break; case TarsStructType.DOUBLE: { n = br.readFloat(8); } break; default: throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return n; } /// 读取byte[] /// 对应Tars类型:SimpleList Uint8List readBytes(int tag, bool isRequire) { var lr = Uint8List(0); if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; switch (t) { case TarsStructType.SIMPLE_LIST: { var hh = HeadData(); readHead(hh); if (hh.type != TarsStructType.BYTE.index) { throw TarsDecodeException( 'type mismatch, tag: $tag,type:${hd.type},${hh.type}'); } var size = readInt(0, true); if (size < 0) { throw TarsDecodeException( 'invalid size, tag: $tag, type: ${hd.type}, ${hh.type} size:$size'); } lr = Uint8List(size); try { lr = br.readBytes(size); } catch (e) { //QTrace.Trace(e.Message); print(e); return Uint8List(0); } } break; case TarsStructType.LIST: { var size = readInt(0, true); if (size < 0) throw TarsDecodeException('size invalid: $size'); lr = Uint8List(size); for (var i = 0; i < size; ++i) { lr[i] = readInt(0, true); } } break; default: throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return lr; } /// 读取Map /// 需要指定键、值的类型 /// 对应Tars类型:Map Map readMap(Map data, int tag, bool isRequire) { Iterable> it = data.entries; MapEntry en = it.first; K k = en.key; V v = en.value; Map map = {}; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; if (t == TarsStructType.MAP) { var size = readInt(0, true); if (size < 0) { throw TarsDecodeException('size invalid:$size'); } for (var i = 0; i < size; ++i) { var mk = read(k, 0, true); var mv = read(v, 1, true); if (mk != null) { if (map.containsKey(mk)) { map[mk] = mv; } else { map.addAll({mk: mv}); } } } } else { throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return map; } /// 读取 k list 结构 Map /// 需要指定键、list值的类型 /// 对应Tars类型:Map Map> readMapList( Map> source, int tag, bool isRequire) { var map = >{}; Iterable>> it = source.entries; MapEntry> en = it.first; K k = en.key; List v = en.value; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; if (t == TarsStructType.MAP) { var size = readInt(0, true); if (size < 0) { throw TarsDecodeException('size invalid:$size'); } for (var i = 0; i < size; ++i) { var mk = read(k, 0, true); var mv = read(v, 1, true); if (mk != null) { if (map.containsKey(mk)) { map[mk] = mv; } else { map.addAll({mk: mv}); } } } } else { throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return map; } /// 读取 k map 结构 Map /// 需要指定键、子Map键值的类型 /// 对应Tars类型:Map Map> readMapMap( Map> source, int tag, bool isRequire) { var map = >{}; Iterable>> it = source.entries; MapEntry> en = it.first; K k = en.key; Map v = en.value; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; if (t == TarsStructType.MAP) { var size = readInt(0, true); if (size < 0) { throw TarsDecodeException('size invalid:$size'); } for (var i = 0; i < size; ++i) { var mk = read(k, 0, true); var mv = readMap(v, 1, true); if (mk != null) { if (map.containsKey(mk)) { map[mk] = mv; } else { map.addAll({mk: mv}); } } } } else { throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return map; } /// 读取列表 /// 对应Tars类型:List List readList(dynamic data, int tag, bool isRequire) { var ls = []; if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; switch (t) { case TarsStructType.LIST: { var size = readInt(0, true); if (size < 0) throw TarsDecodeException('size invalid: $size'); ls = []; for (var i = 0; i < size; ++i) { ls.add(read(data[0], 0, true)); } } break; default: throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return ls; } /// 读取自定义结构 /// 对应Tars类型:TarsStruct TarsStruct readTarsStruct(TarsStruct ts, int tag, bool isRequire) { if (skipToTag(tag)) { var hd = HeadData(); readHead(hd); var t = TarsStructType.values[hd.type]; if (t == TarsStructType.STRUCT_BEGIN) { var copyTs = ts.deepCopy() as TarsStruct; copyTs.readFrom(this); skipToStructEnd(); return copyTs; } else { throw TarsDecodeException('type mismatch.'); } } else if (isRequire) { throw TarsDecodeException('require field not exist.'); } return ts; } String sServerEncoding = "UTF-8"; int setServerEncoding(String se) { sServerEncoding = se; return 0; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_output_stream.dart ================================================ import 'dart:convert'; import 'dart:typed_data'; import './tars_encode_exception.dart'; import './tars_struct.dart'; class BinaryWriter { List buffer; int position = 0; BinaryWriter(this.buffer); int get length => buffer.length; void writeBytes(Uint8List list) { buffer.addAll(list); position += list.length; } void writeInt(int value, int len) { var b = Uint8List(len).buffer; var bytes = ByteData.view(b); if (len == 1) { //写入byte bytes.setUint8(0, value.toUnsigned(8)); } if (len == 2) { bytes.setInt16(0, value, Endian.big); } if (len == 4) { bytes.setInt32(0, value, Endian.big); } if (len == 8) { bytes.setInt64(0, value, Endian.big); } buffer.addAll(bytes.buffer.asUint8List()); position += len; } void writeDouble(double value, int len) { var b = Uint8List(len).buffer; var bytes = ByteData.view(b); if (len == 4) { bytes.setFloat32(0, value, Endian.big); } if (len == 8) { bytes.setFloat64(0, value, Endian.big); } buffer.addAll(bytes.buffer.asUint8List()); position += len; } } class TarsOutputStream { late BinaryWriter bw; TarsOutputStream({Uint8List? ls}) { if (ls != null) { bw = BinaryWriter(ls); } else { bw = BinaryWriter([]); } } void writeHead(int type, int tag) { if (tag < 15) { var b = ((tag << 4) | type); try { bw.writeInt(b, 1); } catch (e) { print(e.toString()); } } else if (tag < 256) { try { var b = ((15 << 4) | type); { bw.writeInt(b, 1); bw.writeInt(tag, 1); } } catch (e) { print('${toString()} writeHead: $e'); } } else { throw TarsEncodeException('tag is too large: $tag'); } } void write(dynamic data, int tag) { if (data is int || data == int) { writeInt(data, tag); } else if (data is double || data == double) { writeDouble(data, tag); } else if (data is bool || data == bool) { writeBool(data, tag); } else if (data is Uint8List || data == Uint8List) { writeUint8List(data, tag); } else if (data is String || data == String) { writeString(data, tag); } else if (data is List || data == List) { writeList(data, tag); } else if (data is Map || data == Map) { writeMap(data, tag); } else if (data is TarsStruct || data == TarsStruct) { writeTarsStruct(data, tag); } else { throw TarsEncodeException('type:${data.runtimeType} not supported.'); } } /// 写入bool /// 对应Tars类型:int1 void writeBool(bool b, int tag) { writeByte(b ? 1 : 0, tag); } /// 写入字节 /// 对应Tars类型:int1 void writeByte(int b, int tag) { //紧跟1个字节整型数据 if (b == 0) { writeHead(TarsStructType.ZERO_TAG.index, tag); } else { writeHead(TarsStructType.BYTE.index, tag); try { bw.writeInt(b, 1); } catch (e) { print(e); } } } /// 写入整数型 /// 对应Tars类型:int1、int2、int4、int8 void writeInt(int n, int tag) { //写入byte //紧跟1个字节整型数据 if (n >= -128 && n <= 127) { writeByte(n, tag); return; } //int16 //紧跟2个字节整型数据 if (n >= -32768 && n <= 32767) { writeHead(TarsStructType.SHORT.index, tag); bw.writeInt(n, 2); return; } //int32 //紧跟4个字节整型数据 if (n >= -2147483648 && n <= 2147483647) { writeHead(TarsStructType.INT.index, tag); bw.writeInt(n, 4); return; } //int64 //紧跟8个字节整型数据 if (n >= -9223372036854775808 && n <= 9223372036854775807) { writeHead(TarsStructType.LONG.index, tag); bw.writeInt(n, 8); return; } } /// 写入浮点数 /// 对应Tars类型:float void writeFloat(double n, int tag) { //紧跟4个字节浮点型数据 writeHead(TarsStructType.FLOAT.index, tag); bw.writeDouble(n, 4); } /// 写入双精度浮点数(Double) /// 对应Tars类型:double void writeDouble(double n, int tag) { //紧跟8个字节浮点型数据 writeHead(TarsStructType.DOUBLE.index, tag); bw.writeDouble(n, 8); } /// 写入字符串 /// 对应Tars类型:string1、string4 void writeString(String s, int tag) { //string1:紧跟1个字节长度,再跟内容 //string4:紧跟4个字节长度,再跟内容 var bytes = utf8.encode(s); if (bytes.isEmpty) { writeHead(TarsStructType.STRING1.index, tag); bw.writeInt(0, 1); return; } if (bytes.length > 255) { writeHead(TarsStructType.STRING4.index, tag); bw.writeInt(bytes.length, 4); bw.writeBytes(Uint8List.fromList(bytes)); } else { writeHead(TarsStructType.STRING1.index, tag); bw.writeInt(bytes.length, 1); bw.writeBytes(Uint8List.fromList(bytes)); } } /// 写入byte[] /// 对应Tars类型:SimpleList void writeUint8List(Uint8List ls, int tag) { //简单列表(目前用在byte数组),紧跟一个类型字段(目前只支持byte),紧跟一个整型数据表示长度,再跟byte数据 writeHead(TarsStructType.SIMPLE_LIST.index, tag); writeHead(TarsStructType.BYTE.index, 0); writeInt(ls.length, 0); bw.writeBytes(ls); } /// 写入Map /// 对应Tars类型:Map void writeMap(Map map, int tag) { //紧跟一个整型数据表示Map的大小,再跟[key, value]对列表 writeHead(TarsStructType.MAP.index, tag); writeInt(map.length, 0); for (var item in map.keys) { write(item, 0); write(map[item], 1); } } /// 写入列表 /// 对应Tars类型:List void writeList(List ls, int tag) { //紧跟一个整型数据表示List的大小,再跟元素列表 writeHead(TarsStructType.LIST.index, tag); write(ls.length, 0); for (var item in ls) { write(item, 0); } } /// 写入自定义结构 /// 对应Tars类型:TarsStruct void writeTarsStruct(TarsStruct o, int tag) { writeHead(TarsStructType.STRUCT_BEGIN.index, tag); o.writeTo(this); writeHead(TarsStructType.STRUCT_END.index, 0); } Uint8List toUint8List() { return Uint8List.fromList(bw.buffer); } String sServerEncoding = "UTF-8"; int setServerEncoding(String se) { sServerEncoding = se; return 0; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/codec/tars_struct.dart ================================================ // ignore_for_file: non_constant_identifier_names, constant_identifier_names, no_leading_underscores_for_local_identifiers import 'dart:typed_data'; import './tars_input_stream.dart'; import './tars_output_stream.dart'; import './tars_deep_copyable.dart'; enum TarsStructType { BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, STRING1, STRING4, MAP, LIST, STRUCT_BEGIN, STRUCT_END, ZERO_TAG, SIMPLE_LIST, } abstract class TarsStruct extends DeepCopyable { static int TARS_MAX_STRING_LENGTH = 100 * 1024 * 1024; void writeTo(TarsOutputStream _os); void readFrom(TarsInputStream _is); void displayAsString(StringBuffer sb, int level); Uint8List toByteArray() { TarsOutputStream os = TarsOutputStream(); writeTo(os); return os.toUint8List(); } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/net/base_tars_http.dart ================================================ import 'dart:io'; import 'dart:typed_data'; import 'package:dio/dio.dart'; import 'package:logger/logger.dart'; import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/tup/const.dart'; import 'package:tars_dart/tars/tup/tars_uni_packet.dart'; import 'package:tars_dart/tars/tup/tup_response.dart'; import 'package:tars_dart/tars/tup/tup_result_exception.dart'; //tup网络请求封装 //注意:只支持 PACKET_TYPE_TUP3 = 3 类型的封包 class BaseTarsHttp { final String baseUrl; final String path; final String servantName; final Map headers; var timeOut = 60000; var debugLog = false; late final Dio dio; final logger = Logger(); BaseTarsHttp( this.baseUrl, this.servantName, { this.path = "", this.timeOut = 60000, this.debugLog = false, this.headers = const {}, }) { dio = Dio(BaseOptions( connectTimeout: Duration(seconds: timeOut), baseUrl: baseUrl, responseType: ResponseType.bytes, headers: { HttpHeaders.contentTypeHeader: "application/x-wup", ...headers })); if (debugLog) { dio.interceptors.add(LogInterceptor(responseBody: false)); //开启请求日志 } } //发送http请求,不返回状态码,异常状态码直接抛出异常TupResultException Future tupRequest( String methodName, REQ tReq, RSP tRsp) async { TupResponse response = await tupRequestWithRspCode(methodName, tReq, tRsp); if (response.code == 0) { return response.response!; } else { logger.e("tupDecode decode error:${response.code}"); throw TupResultException(response.code); } } //发送http请求,返回状态码及response Future> tupRequestWithRspCode( String methodName, REQ tReq, RSP tRsp) async { final data = buildRequest(methodName, tReq); dio.options.headers[HttpHeaders.contentLengthHeader] = data.lengthInBytes; logger.d("send tupRequest, methodName:$methodName"); final result = await dio.post>( path, data: Stream.fromIterable(data.map((e) => [e])), ); final value = result.data; return tupResponseDecode(methodName, value!, tRsp); } //发送无response http请求,返回状态码 Future> tupRequestWithRspCodeNoRsp( String methodName, REQ tReq) async { final data = buildRequest(methodName, tReq); dio.options.headers[HttpHeaders.contentLengthHeader] = data.lengthInBytes; logger.d("send tupRequestNoRsp, methodName:$methodName"); final result = await dio.post>( path, data: Stream.fromIterable(data.map((e) => [e])), ); final value = result.data; return tupEmptyResponseDecode(methodName, value!); } //发送无response http请求,不返回状态码,异常状态码直接抛出异常TupResultException Future tupRequestNoRsp(String methodName, REQ tReq) async { TupResponse response = await tupRequestWithRspCodeNoRsp(methodName, tReq); if (response.code == 0) { return; } else { logger.e("tupDecode decode error:${response.code}"); throw TupResultException(response.code); } } //封包 Uint8List buildRequest(String methodName, REQ tReq) { TarsUniPacket encodePack = TarsUniPacket(); encodePack.requestId = 0; encodePack.setTarsVersion(Const.PACKET_TYPE_TUP3); encodePack.setTarsPacketType(Const.PACKET_TYPE_TARSNORMAL); encodePack.servantName = servantName; encodePack.funcName = methodName; encodePack.put("tReq", tReq); Uint8List bytes = encodePack.encode(); return bytes; } //有response解包 TupResponse tupResponseDecode( String methodName, List list, RSP tRsp) { var bytes = Uint8List.fromList(list); BinaryReader br = BinaryReader(bytes); int size = br.readInt(4); logger.d("size:$size"); TarsUniPacket respPack = TarsUniPacket(); respPack.decode(bytes); var code = respPack.get("", 0); logger.d("get tupRequest response, methodName:$methodName, code:$code"); RSP rsp = respPack.get("tRsp", tRsp); return TupResponse(code: code, response: rsp); } //无response解包 TupResponse tupEmptyResponseDecode(String methodName, List list) { var bytes = Uint8List.fromList(list); BinaryReader br = BinaryReader(bytes); int size = br.readInt(4); logger.d("size:$size"); TarsUniPacket respPack = TarsUniPacket(); respPack.decode(bytes); var code = respPack.get("", 0); logger.d("get tupRequest response, methodName:$methodName, code:$code"); return TupResponse(code: code); } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/basic_class_type_util.dart ================================================ class BasicClassTypeUtil { static String dart2UniType(String type, dynamic obj) { if (type == 'String') { return 'string'; } if (type.contains('List')) { return 'list'; } if (type.contains('Map')) { return 'map'; } if (type == 'bool') { return 'bool'; } // 如果是int,需要检查short/ushort/int32/uint32 if (type == 'int') { if (obj is int) { if (obj >= -32768 && obj <= 32767) { return 'short'; } if (obj >= 0 && obj <= 65535) { return 'ushort'; } if (obj >= -2147483648 && obj <= 2147483647) { return 'int32'; } if (obj >= 0 && obj <= 4294967295) { return 'uint32'; } } else { return 'int32'; } } // 检查int64/uint64 if (type == BigInt.one.runtimeType.toString()) { if (obj is BigInt) { if (obj >= BigInt.from(-9223372036854775808) && obj <= BigInt.from(9223372036854775807)) { return 'int64'; } if (obj >= BigInt.zero && obj <= BigInt.parse('18446744073709551615')) { return 'uint64'; } } return 'int64'; } if (type == 'double') { return 'double'; } return type; } /// 将嵌套的类型转成字符串 static String transTypeList(List listType) { var sb = StringBuffer(); for (var i = 0; i < listType.length; i++) { listType[i] = dart2UniType(listType[i], null); } listType = listType.reversed.toList(); for (var i = 0; i < listType.length; i++) { var type = listType[i]; if (type == 'Null') { continue; } if (type == 'list') { listType[i - 1] = '<${listType[i - 1]}'; listType[0] = '${listType[0]}>'; } else if (type == 'map') { listType[i - 1] = '<${listType[i - 1]},'; listType[0] = '${listType[0]}>'; } else if (type == 'Array') { listType[i - 1] = '<${listType[i - 1]}'; listType[0] = '${listType[0]}>'; } } listType = listType.reversed.toList(); for (var s in listType) { sb.write(s); } return sb.toString(); } static Object? createObject(Type type) { if (type == String) { return ''; } if (type == int) { return 0; } if (type == double) { return 0.0; } if (type == bool) { return false; } if (type == BigInt) { return BigInt.zero; } if (type == List) { return []; } if (type == Map) { return {}; } return null; } static T createObjectT() { if (T == String) { return '' as T; } if (T == int) { return 0 as T; } if (T == double) { return 0.0 as T; } if (T == bool) { return false as T; } if (T == BigInt) { return BigInt.zero as T; } if (T == List) { return [] as T; } if (T == Map) { return {} as T; } return null as T; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/const.dart ================================================ // ignore_for_file: non_constant_identifier_names class Const { static String STATUS_GRID_KEY = "STATUS_GRID_KEY"; static String STATUS_DYED_KEY = "STATUS_DYED_KEY"; static String STATUS_GRID_CODE = "STATUS_GRID_CODE"; static String STATUS_SAMPLE_KEY = "STATUS_SAMPLE_KEY"; static String STATUS_RESULT_CODE = "STATUS_RESULT_CODE"; static String STATUS_RESULT_DESC = "STATUS_RESULT_DESC"; static int INVALID_HASH_CODE = -1; static int INVALID_GRID_CODE = -1; static int PACKET_TYPE_TARSNORMAL = 0; static int PACKET_TYPE_TARSONEWAY = 1; static int PACKET_TYPE_TUP = 2; static int PACKET_TYPE_TUP3 = 3; } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/object_create_exception.dart ================================================ class ObjectCreateException implements Exception { // ignore: unused_field late String _message; ObjectCreateException(String message) { _message = message; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/request_packet.dart ================================================ // ignore_for_file: non_constant_identifier_names, avoid_renaming_method_parameters, no_leading_underscores_for_local_identifiers import 'dart:core'; import 'dart:typed_data'; import '/tars/codec/tars_input_stream.dart'; import '/tars/codec/tars_output_stream.dart'; import '/tars/codec/tars_struct.dart'; import '/tars/codec/tars_displayer.dart'; import '/tars/codec/tars_deep_copyable.dart'; class RequestPacket extends TarsStruct { String className() { return "RequestPacket"; } int iVersion = 0; int cPacketType = 0; int iMessageType = 0; int iRequestId = 0; String sServantName = ""; String sFuncName = ""; Uint8List? sBuffer; int iTimeout = 0; Map? context; Map? status; RequestPacket( {this.iVersion = 0, this.cPacketType = 0, this.iMessageType = 0, this.iRequestId = 0, this.sServantName = "", this.sFuncName = "", this.sBuffer, this.iTimeout = 0, this.context, this.status}); @override void writeTo(TarsOutputStream _os) { _os.write(iVersion, 1); _os.write(cPacketType, 2); _os.write(iMessageType, 3); _os.write(iRequestId, 4); _os.write(sServantName, 5); _os.write(sFuncName, 6); _os.write(sBuffer, 7); _os.write(iTimeout, 8); _os.write(context, 9); _os.write(status, 10); } static Uint8List cache_sBuffer = Uint8List.fromList([0x0]); static Map cache_context = {"": ""}; static Map cache_status = {"": ""}; @override void readFrom(TarsInputStream _is) { iVersion = _is.read(iVersion, 1, false); cPacketType = _is.read(cPacketType, 2, false); iMessageType = _is.read(iMessageType, 3, false); iRequestId = _is.read(iRequestId, 4, false); sServantName = _is.read(sServantName, 5, false); sFuncName = _is.read(sFuncName, 6, false); sBuffer = _is.read(cache_sBuffer, 7, false); iTimeout = _is.read(iTimeout, 8, false); context = _is.readMap(cache_context, 9, false); status = _is.readMap(cache_status, 10, false); } @override void displayAsString(StringBuffer _os, int _level) { TarsDisplayer _ds = TarsDisplayer(_os, level: _level); _ds.display(iVersion, "iVersion"); _ds.display(cPacketType, "cPacketType"); _ds.display(iMessageType, "iMessageType"); _ds.display(iRequestId, "iRequestId"); _ds.display(sServantName, "sServantName"); _ds.display(sFuncName, "sFuncName"); _ds.display(sBuffer, "sBuffer"); _ds.display(iTimeout, "iTimeout"); _ds.display(context, "context"); _ds.display(status, "status"); } @override Object deepCopy() { var o = RequestPacket(); o.iVersion = iVersion; o.cPacketType = cPacketType; o.iMessageType = iMessageType; o.iRequestId = iRequestId; o.sServantName = sServantName; o.sFuncName = sFuncName; o.sBuffer = sBuffer; o.iTimeout = iTimeout; if (null != context) { o.context = mapDeepCopy(context!); } if (null != status) { o.status = mapDeepCopy(status!); } return o; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/tars_uni_packet.dart ================================================ import 'dart:typed_data'; import 'uni_packet.dart'; import 'const.dart'; class TarsUniPacket extends UniPacket { TarsUniPacket() { package.iVersion = Const.PACKET_TYPE_TUP3; package.cPacketType = Const.PACKET_TYPE_TARSNORMAL; package.iMessageType = 0; package.iTimeout = 0; package.sBuffer = Uint8List.fromList([0x0]); package.context = {}; package.status = {}; } /// 设置协议版本 void setTarsVersion(int version) { setVersion(version); } /// 设置调用类型 void setTarsPacketType(int packetType) { package.cPacketType = packetType; } /// 设置消息类型 void setTarsMessageType(int messageType) { package.iMessageType = messageType; } /// 设置超时时间 void setTarsTimeout(int timeout) { package.iTimeout = timeout; } /// 设置参数编码内容 void setTarsBuffer(Uint8List buffer) { package.sBuffer = buffer; } /// 设置上下文 void setTarsContext(Map context) { package.context = context; } /// 设置特殊消息的状态值 void setTarsStatus(Map status) { package.status = status; } /// 获取协议版本 int getTarsVersion() { return package.iVersion; } /// 获取调用类型 int getTarsPacketType() { return package.cPacketType; } /// 获取消息类型 int getTarsMessageType() { return package.iMessageType; } /// 获取超时时间 int getTarsTimeout() { return package.iTimeout; } /// 获取参数编码后内容 Uint8List? getTarsBuffer() { return package.sBuffer; } /// 获取上下文信息 Map? getTarsContext() { return package.context; } /// 获取特殊消息的状态值 Map? getTarsStatus() { return package.status; } /// 获取调用tars的返回值 int getTarsResultCode() { int result = 0; try { String? rcode = package.status?[Const.STATUS_RESULT_CODE]; result = (rcode != null ? int.tryParse(rcode) : 0)!; } catch (e) { print('getTarsResultCode exception: $e'); return 0; } return result; } /// 获取调用tars的返回描述 String getTarsResultDesc() { String? rdesc = package.status?[Const.STATUS_RESULT_DESC]; String result = rdesc ?? ""; return result; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/tup_response.dart ================================================ class TupResponse { int code = 0; T? response; TupResponse({this.code = 0, this.response}); } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/tup_result_exception.dart ================================================ class TupResultException implements Exception { late int code; late String? message; TupResultException(this.code, {this.message}); @override String toString() { return '{code: $code, message: $message}'; } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/uni_attribute.dart ================================================ // ignore_for_file: no_leading_underscores_for_local_identifiers import 'dart:core'; import 'dart:typed_data'; import 'package:tars_dart/tars/tup/basic_class_type_util.dart'; import '/tars/codec/tars_input_stream.dart'; import '/tars/codec/tars_output_stream.dart'; import '/tars/codec/tars_struct.dart'; import 'const.dart'; import 'object_create_exception.dart'; class UniAttribute extends TarsStruct { /// 精简版tup,PACKET_TYPE_TUP3类型 Map newData = {}; //PACKET_TYPE_TUP类型 Map> oldData = {}; /// 存储get后的数据 避免多次解析 Map cachedData = {}; int version = Const.PACKET_TYPE_TUP; String encodeName = 'UTF-8'; final TarsInputStream _is = TarsInputStream(null); /// 清除缓存的解析过的数据 void clearCacheData() { cachedData.clear(); } bool isEmpty() { if (version == Const.PACKET_TYPE_TUP3) { return newData.isEmpty; } else { return oldData.isEmpty; } } int get length { if (version == Const.PACKET_TYPE_TUP3) { return newData.length; } else { return oldData.length; } } bool containsKey(String key) { if (version == Const.PACKET_TYPE_TUP3) { return newData.containsKey(key); } else { return oldData.containsKey(key); } } /// 放入一个元素 /// @param /// @param name /// @param t void put(String name, T t) { if (name.isEmpty) { throw ArgumentError("put key can not is null"); } if (t == null) { throw ArgumentError("put value can not is null"); } TarsOutputStream _out = TarsOutputStream(); _out.setServerEncoding(encodeName); _out.write(t, 0); Uint8List sBuffer = _out.toUint8List(); if (version == Const.PACKET_TYPE_TUP3) { cachedData.remove(name); if (newData.containsKey(name)) { newData[name] = sBuffer; } else { newData[name] = sBuffer; } } else { var listType = []; checkObjectType(listType, t); var className = BasicClassTypeUtil.transTypeList(listType); var pair = {}; pair[className] = sBuffer; cachedData.remove(name); oldData[name] = pair; } } void checkObjectType(List listType, dynamic o) { if (o == null) { throw Exception('object is null'); } if (o is List) { listType.add('list'); if (o.isNotEmpty) { checkObjectType(listType, o[0]); } else { listType.add('?'); } } else if (o is Map) { listType.add('map'); if (o.isNotEmpty) { var key = o.keys.first; listType.add( BasicClassTypeUtil.dart2UniType(key.runtimeType.toString(), key)); checkObjectType(listType, o[key]); } else { listType.add('?'); listType.add('?'); // throw ArgumentError("map cannot be empty"); } } else if (o is Iterable) { listType.add('list'); // 如果是Iterable但不是List,可以处理其他类型的集合 var iterator = o.iterator; if (iterator.moveNext()) { checkObjectType(listType, iterator.current); } else { listType.add('?'); } } else { listType .add(BasicClassTypeUtil.dart2UniType(o.runtimeType.toString(), o)); } } Object decodeData(Uint8List data, Object? proxy) { _is.wrap(data); _is.setServerEncoding(encodeName); Object o = _is.read(proxy, 0, true); return o; } /// 获取tup精简版本编码的数据,兼容旧版本tup /// @param /// @param name /// @param proxy /// @return /// @throws ObjectCreateException T getByClass(String name, T proxy) { Object? obj; if (version == Const.PACKET_TYPE_TUP3) { if (!newData.containsKey(name)) { return obj as T; } else if (cachedData.containsKey(name)) { obj = cachedData[name]; return obj as T; } else { try { Uint8List data = newData[name] as Uint8List; Object o = decodeData(data, proxy!); saveDataCache(name, o); return o as T; } catch (ex) { throw ObjectCreateException(ex.toString()); } } } else { //兼容tup2 return get2(name); } } // 获取一个元素,只能用于tup版本2,如果待获取的数据为tup3,则抛异常 T get2(String name, {T? proxy}) { if (version == Const.PACKET_TYPE_TUP3) { throw Exception('data is not in tup2 format'); } if (cachedData.containsKey(name)) { return cachedData[name] as T; } if (!oldData.containsKey(name)) { return null as T; } var data = oldData[name]!; var className = data.keys.first; var sBuffer = data[className]!; var o = decodeData(sBuffer, proxy); saveDataCache(name, o); return o as T; } /// 获取一个元素,tup新旧版本都兼容 /// @param Name /// @param DefaultObj /// @return /// @throws ObjectCreateException T get(String name, T defaultObj) { try { Object? result; if (version == Const.PACKET_TYPE_TUP3) { result = getByClass(name, defaultObj); } else { //tup2 return get2(name, proxy: defaultObj); } if (result == null) { return defaultObj; } return result as T; } catch (ex) { return defaultObj; } } void saveDataCache(String name, Object o) { cachedData[name] = o; } Uint8List encode() { TarsOutputStream _os = TarsOutputStream(); _os.setServerEncoding(encodeName); if (version == Const.PACKET_TYPE_TUP3) { _os.write(newData, 0); } else { _os.write(oldData, 0); } return _os.toUint8List(); } void decode(Uint8List buffer, {int index = 0}) { //try tup3 try { _is.wrap(buffer, pos: index); _is.setServerEncoding(encodeName); version = Const.PACKET_TYPE_TUP; oldData = _is.readMapMap(oldData, 0, false); } catch (ex) { version = Const.PACKET_TYPE_TUP3; _is.wrap(buffer, pos: index); _is.setServerEncoding(encodeName); newData = _is.readMap({ "": Uint8List.fromList([0x0]) }, 0, false); } } @override void writeTo(TarsOutputStream _os) { if (version == Const.PACKET_TYPE_TUP3) { _os.write(newData, 0); } else { _os.write(oldData, 0); } } @override void readFrom(TarsInputStream _is) { if (version == Const.PACKET_TYPE_TUP3) { newData = { "": Uint8List.fromList([0x0]) }; _is.readMap(newData, 0, false); } else { oldData = _is.readMapMap(oldData, 0, false); } } @override Object deepCopy() { throw UnimplementedError(); } @override void displayAsString(StringBuffer sb, int level) { throw UnimplementedError(); } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/uni_packet.dart ================================================ // ignore_for_file: no_leading_underscores_for_local_identifiers import 'package:tars_dart/tars/codec/tars_input_stream.dart'; import 'package:tars_dart/tars/codec/tars_output_stream.dart'; import 'package:tars_dart/tars/tup/write_buffer.dart'; import 'const.dart'; import 'request_packet.dart'; import 'uni_attribute.dart'; class UniPacket extends UniAttribute { static const int kUniPacketHeadSize = 4; RequestPacket package = RequestPacket(); /// 获取请求的service名字 /// /// @return String get servantName { return package.sServantName; } set servantName(String value) { package.sServantName = value; } /// 获取请求的函数名字 /// /// @return String get funcName { return package.sFuncName; } set funcName(String value) { package.sFuncName = value; } /// 获取消息序列号 /// /// @return int get requestId { return package.iRequestId; } set requestId(int value) { package.iRequestId = value; } UniPacket() { package.iVersion = Const.PACKET_TYPE_TUP3; } void setVersion(int iVer) { version = iVer; package.iVersion = iVer; } int getVersion() { return package.iVersion; } /// 将put的对象进行编码 @override Uint8List encode() { if (package.sServantName.compareTo("") == 0) { throw ArgumentError("servantName can not is null"); } if (package.sFuncName.compareTo("") == 0) { throw ArgumentError("funcName can not is null"); } TarsOutputStream _os = TarsOutputStream(); _os.setServerEncoding(encodeName); if (package.iVersion == Const.PACKET_TYPE_TUP) { throw UnimplementedError(); } else { _os.write(newData, 0); } package.sBuffer = _os.toUint8List(); _os = TarsOutputStream(); _os.setServerEncoding(encodeName); writeTo(_os); Uint8List body = _os.toUint8List(); int size = body.lengthInBytes; final WriteBuffer buffer = WriteBuffer(); buffer.putInt32(size + kUniPacketHeadSize, endian: Endian.big); buffer.putUint8List(body); return buffer.done().buffer.asUint8List(); } /// 对传入的数据进行解码 填充可get的对象 @override void decode(Uint8List buffer, {int index = 0}) { if (buffer.lengthInBytes < kUniPacketHeadSize) { throw ArgumentError("Decode namespace must include size head"); } try { TarsInputStream _is = TarsInputStream(buffer, pos: kUniPacketHeadSize + index); _is.setServerEncoding(encodeName); //解码出RequestPacket包 readFrom(_is); //设置tup版本 version = package.iVersion; _is = TarsInputStream(package.sBuffer); _is.setServerEncoding(encodeName); if (package.iVersion == Const.PACKET_TYPE_TUP) { oldData = _is.readMapMap( >{ "": { "": Uint8List.fromList([0x0]) } }, 0, false); } else { newData = _is.readMap({ "": Uint8List.fromList([0x0]) }, 0, false); } } catch (e) { print('decode exception: $e'); rethrow; } } @override void writeTo(TarsOutputStream _os) { package.writeTo(_os); } @override void readFrom(TarsInputStream _is) { package.readFrom(_is); } } ================================================ FILE: simple_live_core/packages/tars_dart/lib/tars/tup/write_buffer.dart ================================================ // Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:math' as math; import 'dart:typed_data'; export 'dart:typed_data' show ByteData, Endian, Float32List, Float64List, Int32List, Int64List, Uint8List; /// Write-only buffer for incrementally building a [ByteData] instance. /// /// A WriteBuffer instance can be used only once. Attempts to reuse will result /// in [StateError]s being thrown. /// /// The byte order used is [Endian.host] throughout. class WriteBuffer { /// Creates an interface for incrementally building a [ByteData] instance. /// [startCapacity] determines the start size of the [WriteBuffer] in bytes. /// The closer that value is to the real size used, the better the /// performance. factory WriteBuffer({int startCapacity = 8}) { assert(startCapacity > 0); final ByteData eightBytes = ByteData(8); final Uint8List eightBytesAsList = eightBytes.buffer.asUint8List(); return WriteBuffer._( Uint8List(startCapacity), eightBytes, eightBytesAsList); } WriteBuffer._(this._buffer, this._eightBytes, this._eightBytesAsList); Uint8List _buffer; int _currentSize = 0; bool _isDone = false; final ByteData _eightBytes; final Uint8List _eightBytesAsList; static final Uint8List _zeroBuffer = Uint8List(8); void _add(int byte) { if (_currentSize == _buffer.length) { _resize(); } _buffer[_currentSize] = byte; _currentSize += 1; } void _append(Uint8List other) { final int newSize = _currentSize + other.length; if (newSize >= _buffer.length) { _resize(newSize); } _buffer.setRange(_currentSize, newSize, other); _currentSize += other.length; } void _addAll(Uint8List data, [int start = 0, int? end]) { final int newEnd = end ?? _eightBytesAsList.length; final int newSize = _currentSize + (newEnd - start); if (newSize >= _buffer.length) { _resize(newSize); } _buffer.setRange(_currentSize, newSize, data); _currentSize = newSize; } void _resize([int? requiredLength]) { final int doubleLength = _buffer.length * 2; final int newLength = math.max(requiredLength ?? 0, doubleLength); final Uint8List newBuffer = Uint8List(newLength); newBuffer.setRange(0, _buffer.length, _buffer); _buffer = newBuffer; } /// Write a Uint8 into the buffer. void putUint8(int byte) { assert(!_isDone); _add(byte); } /// Write a Uint16 into the buffer. void putUint16(int value, {Endian? endian}) { assert(!_isDone); _eightBytes.setUint16(0, value, endian ?? Endian.host); _addAll(_eightBytesAsList, 0, 2); } /// Write a Uint32 into the buffer. void putUint32(int value, {Endian? endian}) { assert(!_isDone); _eightBytes.setUint32(0, value, endian ?? Endian.host); _addAll(_eightBytesAsList, 0, 4); } /// Write an Int32 into the buffer. void putInt32(int value, {Endian? endian}) { assert(!_isDone); _eightBytes.setInt32(0, value, endian ?? Endian.host); _addAll(_eightBytesAsList, 0, 4); } /// Write an Int64 into the buffer. void putInt64(int value, {Endian? endian}) { assert(!_isDone); _eightBytes.setInt64(0, value, endian ?? Endian.host); _addAll(_eightBytesAsList, 0, 8); } /// Write an Float64 into the buffer. void putFloat64(double value, {Endian? endian}) { assert(!_isDone); _alignTo(8); _eightBytes.setFloat64(0, value, endian ?? Endian.host); _addAll(_eightBytesAsList); } /// Write all the values from a [Uint8List] into the buffer. void putUint8List(Uint8List list) { assert(!_isDone); _append(list); } /// Write all the values from an [Int32List] into the buffer. void putInt32List(Int32List list) { assert(!_isDone); _alignTo(4); _append(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); } /// Write all the values from an [Int64List] into the buffer. void putInt64List(Int64List list) { assert(!_isDone); _alignTo(8); _append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); } /// Write all the values from a [Float32List] into the buffer. void putFloat32List(Float32List list) { assert(!_isDone); _alignTo(4); _append(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); } /// Write all the values from a [Float64List] into the buffer. void putFloat64List(Float64List list) { assert(!_isDone); _alignTo(8); _append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); } void _alignTo(int alignment) { assert(!_isDone); final int mod = _currentSize % alignment; if (mod != 0) { _addAll(_zeroBuffer, 0, alignment - mod); } } /// Finalize and return the written [ByteData]. ByteData done() { if (_isDone) { throw StateError( 'done() must not be called more than once on the same $runtimeType.'); } final ByteData result = _buffer.buffer.asByteData(0, _currentSize); _buffer = Uint8List(0); _isDone = true; return result; } } /// Read-only buffer for reading sequentially from a [ByteData] instance. /// /// The byte order used is [Endian.host] throughout. class ReadBuffer { /// Creates a [ReadBuffer] for reading from the specified [data]. ReadBuffer(this.data); /// The underlying data being read. final ByteData data; /// The position to read next. int _position = 0; /// Whether the buffer has data remaining to read. bool get hasRemaining => _position < data.lengthInBytes; /// Reads a Uint8 from the buffer. int getUint8() { return data.getUint8(_position++); } /// Reads a Uint16 from the buffer. int getUint16({Endian? endian}) { final int value = data.getUint16(_position, endian ?? Endian.host); _position += 2; return value; } /// Reads a Uint32 from the buffer. int getUint32({Endian? endian}) { final int value = data.getUint32(_position, endian ?? Endian.host); _position += 4; return value; } /// Reads an Int32 from the buffer. int getInt32({Endian? endian}) { final int value = data.getInt32(_position, endian ?? Endian.host); _position += 4; return value; } /// Reads an Int64 from the buffer. int getInt64({Endian? endian}) { final int value = data.getInt64(_position, endian ?? Endian.host); _position += 8; return value; } /// Reads a Float64 from the buffer. double getFloat64({Endian? endian}) { _alignTo(8); final double value = data.getFloat64(_position, endian ?? Endian.host); _position += 8; return value; } /// Reads the given number of Uint8s from the buffer. Uint8List getUint8List(int length) { final Uint8List list = data.buffer.asUint8List(data.offsetInBytes + _position, length); _position += length; return list; } /// Reads the given number of Int32s from the buffer. Int32List getInt32List(int length) { _alignTo(4); final Int32List list = data.buffer.asInt32List(data.offsetInBytes + _position, length); _position += 4 * length; return list; } /// Reads the given number of Int64s from the buffer. Int64List getInt64List(int length) { _alignTo(8); final Int64List list = data.buffer.asInt64List(data.offsetInBytes + _position, length); _position += 8 * length; return list; } /// Reads the given number of Float32s from the buffer Float32List getFloat32List(int length) { _alignTo(4); final Float32List list = data.buffer.asFloat32List(data.offsetInBytes + _position, length); _position += 4 * length; return list; } /// Reads the given number of Float64s from the buffer. Float64List getFloat64List(int length) { _alignTo(8); final Float64List list = data.buffer.asFloat64List(data.offsetInBytes + _position, length); _position += 8 * length; return list; } void _alignTo(int alignment) { final int mod = _position % alignment; if (mod != 0) { _position += alignment - mod; } } } ================================================ FILE: simple_live_core/packages/tars_dart/pubspec.yaml ================================================ name: tars_dart description: Dart Support Library For Tars RPC framework version: 0.1.0 homepage: "https://github.com/brooklet/TarsFlutter" environment: sdk: '>=3.0.5 <4.0.0' dependencies: dio: ^5.7.0 logger: ^2.5.0 dev_dependencies: lints: ^2.0.0 test: ^1.21.0 ================================================ FILE: simple_live_core/pubspec.yaml ================================================ name: simple_live_core version: 1.0.3 description: "聚合直播核心库" repository: https://github.com/xiaoyaocz/dart_simple_live publish_to: "none" environment: sdk: '>=3.10.0' dependencies: dio: ^5.5.0+1 logger: ^2.4.0 web_socket_channel: ^3.0.1 html_unescape: ^2.0.0 protobuf: ^3.1.0 crypto: ^3.0.3 brotli: ^0.6.0 tars_dart: path: ./packages/tars_dart fixnum: ^1.1.0 dart_quickjs: git: url: https://github.com/xiaoyaocz/dart_quickjs dev_dependencies: lints: ^2.0.0 test: ^1.21.0 ================================================ FILE: simple_live_core/test/simple_live_core_test.dart ================================================ import 'package:simple_live_core/simple_live_core.dart'; import 'package:test/test.dart'; void testSite(LiveSite site) async { var rooms = []; test('getRecommendRooms', () async { final result = await site.getRecommendRooms(); expect(result, isNotNull); expect(result.items, isNotEmpty); rooms = result.items; for (var item in rooms) { expect(item.roomId, isNotEmpty); expect(item.title, isNotEmpty); expect(item.cover, isNotEmpty); expect(item.userName, isNotEmpty); print(item); } }); var categores = []; test('getCategores', () async { categores = await site.getCategores(); expect(categores, isNotEmpty); for (var item in categores) { expect(item.name, isNotEmpty); for (var subItem in item.children) { expect(subItem.name, isNotEmpty); expect(subItem.id, isNotEmpty); expect(subItem.parentId, isNotEmpty); } print('${item.name}\n${item.children}'); } }); test('getCategoryRooms', () async { var result = await site.getCategoryRooms(categores.first.children.first); expect(result, isNotNull); expect(result.items, isNotEmpty); for (var item in result.items) { expect(item.roomId, isNotEmpty); expect(item.title, isNotEmpty); expect(item.cover, isNotEmpty); expect(item.userName, isNotEmpty); print(item); } }); test('searchRooms', () async { var result = await site.searchRooms('LOL'); expect(result, isNotNull); expect(result.items, isNotEmpty); for (var item in result.items) { expect(item.roomId, isNotEmpty); expect(item.title, isNotEmpty); expect(item.cover, isNotEmpty); expect(item.userName, isNotEmpty); print(item); } }); test('searchAnchors', () async { // 跳过抖音测试此项 if (site is DouyinSite) { return; } var result = await site.searchAnchors('联盟'); expect(result, isNotNull); expect(result.items, isNotEmpty); for (var item in result.items) { expect(item.roomId, isNotEmpty); expect(item.userName, isNotEmpty); print(item); } }); LiveRoomDetail? roomDetail; test('getRoomDetail', () async { roomDetail = await site.getRoomDetail(roomId: rooms.first.roomId); expect(roomDetail, isNotNull); expect(roomDetail?.roomId, isNotEmpty); expect(roomDetail?.danmakuData, isNotNull); print(roomDetail); }); List playQualities = []; test('getPlayQuality', () async { playQualities = await site.getPlayQualites(detail: roomDetail!); expect(playQualities, isNotEmpty); for (var item in playQualities) { expect(item.quality, isNotEmpty); expect(item.data, isNotNull); print(item); } }); test('getPlayUrls', () async { var url = await site.getPlayUrls( detail: roomDetail!, quality: playQualities.first); expect(url, isNotNull); expect(url.urls, isNotEmpty); print(url.urls.join('\n\n')); }); test('getDanmaku', () async { var danmaku = site.getDanmaku(); expect(danmaku, isNotNull); expect(danmaku, isA()); var closed = false; var ready = false; danmaku.onReady = () { print('ready'); ready = true; }; danmaku.onClose = (msg) { print('onClose $msg'); closed = true; }; var msgCount = 0; danmaku.onMessage = (LiveMessage msg) { print('onMessage ${msg.type} ${msg.message}'); msgCount++; }; await danmaku.start(roomDetail!.danmakuData); // 接收30秒的弹幕 await Future.delayed(const Duration(seconds: 30)); expect(ready, isTrue); expect(closed, isFalse); expect(msgCount, greaterThan(0)); await danmaku.stop(); }, timeout: const Timeout(Duration(seconds: 40))); } void main() { CoreLog.requestLogType = RequestLogType.short; group('bilibili tests', () { testSite(BiliBiliSite()); }); group('douyu tests', () { testSite(DouyuSite()); }); group('huya tests', () { testSite(HuyaSite()); }); group('douyin tests', () { testSite(DouyinSite()); }); } ================================================ FILE: simple_live_tv_app/.fvmrc ================================================ { "flutter": "3.38.3" } ================================================ FILE: simple_live_tv_app/.gitignore ================================================ # Miscellaneous *.class *.log *.pyc *.swp .DS_Store .atom/ .buildlog/ .history .svn/ migrate_working_dir/ # IntelliJ related *.iml *.ipr *.iws .idea/ # The .vscode folder contains launch configuration and tasks you configure in # VS Code which you may wish to be included in version control, so this line # is commented out by default. #.vscode/ # Flutter/Dart/Pub related **/doc/api/ **/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies .packages .pub-cache/ .pub/ /build/ # Symbolication related app.*.symbols # Obfuscation related app.*.map.json # Android Studio will place build artifacts here /android/app/debug /android/app/profile /android/app/release # FVM Version Cache .fvm/ ================================================ FILE: simple_live_tv_app/.metadata ================================================ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # # This file should be version controlled and should not be manually edited. version: revision: "d693b4b9dbac2acd4477aea4555ca6dcbea44ba2" channel: "stable" project_type: app # Tracks metadata for the flutter migrate command migration: platforms: - platform: root create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 - platform: android create_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 base_revision: d693b4b9dbac2acd4477aea4555ca6dcbea44ba2 # User provided section # List of Local paths (relative to this file) that should be # ignored by the migrate tool. # # Files that are not part of the templates will be ignored by default. unmanaged_files: - 'lib/main.dart' - 'ios/Runner.xcodeproj/project.pbxproj' ================================================ FILE: simple_live_tv_app/README.md ================================================ # simple_live_tv_app Simple Live Android TV APP ================================================ FILE: simple_live_tv_app/analysis_options.yaml ================================================ # This file configures the analyzer, which statically analyzes Dart code to # check for errors, warnings, and lints. # # The issues identified by the analyzer are surfaced in the UI of Dart-enabled # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be # invoked from the command line by running `flutter analyze`. # The following line activates a set of recommended lints for Flutter apps, # packages, and plugins designed to encourage good coding practices. include: package:flutter_lints/flutter.yaml linter: # The lint rules applied to this project can be customized in the # section below to disable rules from the `package:flutter_lints/flutter.yaml` # included above or to enable additional rules. A list of all available lints # and their documentation is published at https://dart.dev/lints. # # Instead of disabling a lint rule for the entire project in the # section below, it can also be suppressed for a single line of code # or a specific dart file by using the `// ignore: name_of_lint` and # `// ignore_for_file: name_of_lint` syntax on the line or in the file # producing the lint. rules: # avoid_print: false # Uncomment to disable the `avoid_print` rule # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options ================================================ FILE: simple_live_tv_app/android/.gitignore ================================================ gradle-wrapper.jar /.gradle /captures/ /gradlew /gradlew.bat /local.properties GeneratedPluginRegistrant.java .cxx/ # Remember to never publicly share your keystore. # See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks ================================================ FILE: simple_live_tv_app/android/app/build.gradle.kts ================================================ import java.util.Properties import java.io.FileInputStream plugins { id("com.android.application") id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id("dev.flutter.flutter-gradle-plugin") } val keystoreProperties = Properties() val keystorePropertiesFile = rootProject.file("key.properties") if (keystorePropertiesFile.exists()) { keystoreProperties.load(FileInputStream(keystorePropertiesFile)) } android { namespace = "com.xycz.simple_live_tv" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion compileOptions { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId = "com.xycz.simple_live_tv" // You can update the following values to match your application needs. // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion versionCode = flutter.versionCode versionName = flutter.versionName } signingConfigs { create("release") { keyAlias = keystoreProperties["keyAlias"] as String keyPassword = keystoreProperties["keyPassword"] as String storeFile = keystoreProperties["storeFile"]?.let { file(it) } storePassword = keystoreProperties["storePassword"] as String isV1SigningEnabled = true isV2SigningEnabled = true } } buildTypes { release { // Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.getByName("release") isMinifyEnabled = true isShrinkResources = true proguardFiles( // Default file with automatically generated optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } } flutter { source = "../.." } ================================================ FILE: simple_live_tv_app/android/app/proguard-rules.pro ================================================ #Flutter Wrapper -keep class io.flutter.app.** { *; } -keep class io.flutter.plugin.** { *; } -keep class io.flutter.util.** { *; } -keep class io.flutter.view.** { *; } -keep class io.flutter.** { *; } -keep class io.flutter.plugins.** { *; } -keep class de.prosiebensat1digital.** { *; } -dontwarn io.flutter.embedding.** -ignorewarnings ================================================ FILE: simple_live_tv_app/android/app/src/debug/AndroidManifest.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/kotlin/com/xycz/simple_live_tv/MainActivity.kt ================================================ package com.xycz.simple_live_tv import io.flutter.embedding.android.FlutterActivity class MainActivity: FlutterActivity() { } ================================================ FILE: simple_live_tv_app/android/app/src/main/res/drawable/launch_background.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/res/drawable-v21/launch_background.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/res/mipmap-anydpi-v26/ic_banner.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/res/values/ic_banner_background.xml ================================================ #FFFFFF ================================================ FILE: simple_live_tv_app/android/app/src/main/res/values/styles.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/res/values-night/styles.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/main/res/xml/network_security_config.xml ================================================ ================================================ FILE: simple_live_tv_app/android/app/src/profile/AndroidManifest.xml ================================================ ================================================ FILE: simple_live_tv_app/android/build.gradle.kts ================================================ allprojects { repositories { google() mavenCentral() } } val newBuildDir: Directory = rootProject.layout.buildDirectory .dir("../../build") .get() rootProject.layout.buildDirectory.value(newBuildDir) subprojects { val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) project.layout.buildDirectory.value(newSubprojectBuildDir) } subprojects { project.evaluationDependsOn(":app") } tasks.register("clean") { delete(rootProject.layout.buildDirectory) } ================================================ FILE: simple_live_tv_app/android/gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip ================================================ FILE: simple_live_tv_app/android/gradle.properties ================================================ org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true ================================================ FILE: simple_live_tv_app/android/settings.gradle.kts ================================================ pluginManagement { val flutterSdkPath = run { val properties = java.util.Properties() file("local.properties").inputStream().use { properties.load(it) } val flutterSdkPath = properties.getProperty("flutter.sdk") require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } flutterSdkPath } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") repositories { google() mavenCentral() gradlePluginPortal() } } plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.9.1" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false } include(":app") ================================================ FILE: simple_live_tv_app/assets/lotties/empty.json ================================================ {"v":"4.7.0","fr":25,"ip":0,"op":50,"w":120,"h":120,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"ruoi","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p967_0p167_0p033"],"t":35,"s":[100],"e":[0]},{"t":49}]},"r":{"a":0,"k":0},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0,"y":0},"n":"0p833_0p833_0_0","t":0,"s":[57.361,61.016,0],"e":[57.699,41.796,0],"to":[-4.67500305175781,-4.12800598144531,0],"ti":[-13.9099960327148,5.27300262451172,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10.219,"s":[57.699,41.796,0],"e":[79.084,33.982,0],"to":[12.8159942626953,-4.85800170898438,0],"ti":[-4.54498291015625,3.73400115966797,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":19.445,"s":[79.084,33.982,0],"e":[59.691,9.121,0],"to":[6.61601257324219,-5.43799591064453,0],"ti":[20.0290069580078,1.20700073242188,0]},{"t":35}]},"a":{"a":0,"k":[60.531,10.945,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.994,0],[0,-0.994],[0.995,0],[0,0.994]],"o":[[0.995,0],[0,0.994],[-0.994,0],[0,-0.994]],"v":[[-0.001,-1.801],[1.801,-0.001],[-0.001,1.801],[-1.801,-0.001]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[62.4,13.144],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.422,0],[0,-1.422],[1.421,0],[0,1.422]],"o":[[1.421,0],[0,1.422],[-1.422,0],[0,-1.422]],"v":[[0.001,-2.574],[2.574,0],[0.001,2.574],[-2.574,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[64.145,9.606],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.996,0],[0,-1.996],[1.996,0],[0,1.996]],"o":[[1.996,0],[0,1.996],[-1.996,0],[0,-1.996]],"v":[[0,-3.614],[3.614,0],[0,3.614],[-3.614,0]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.4235294117647059,0.4235294117647059,0.4235294117647059,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0.7},"lc":1,"lj":1,"ml":10,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[1,1,1,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[57.957,10.552],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"tr","p":{"a":0,"k":[60.531,10.941],"ix":2},"a":{"a":0,"k":[60.531,10.941],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"ruoi","np":3,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.967]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p967_0p167_0p033"],"t":35,"s":[100],"e":[0]},{"t":49}]},"r":{"a":0,"k":0},"p":{"a":0,"k":[-0.75,-0.75,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-13.91,5.273],[-4.545,3.734],[20.029,1.207]],"o":[[-4.675,-4.128],[12.816,-4.858],[6.616,-5.438],[0,0]],"v":[[-7.383,24.76],[-7.046,5.54],[14.34,-2.273],[-3.178,-24.76]],"c":false}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.34901960784313724,0.3686274509803922,0.4,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":1},"lc":2,"lj":2,"d":[{"n":"d","nm":"dash","v":{"a":0,"k":2.028}},{"n":"g","nm":"gap","v":{"a":0,"k":2.028}},{"n":"o","nm":"offset","v":{"a":0,"k":0}}],"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"tr","p":{"a":0,"k":[67.87,37.631],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.953]},"o":{"x":[0.167],"y":[0.033]},"n":["0p833_0p953_0p167_0p033"],"t":0,"s":[0],"e":[100]},{"t":35}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"im_emptyBox Outlines","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[60,60,0]},"a":{"a":0,"k":[60,60,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-0.001,-16.607],[-32.143,-0.002],[-0.001,16.607],[32.144,-0.002]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8,0.82,0.851,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,55.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[12.856,-23.249],[0,-16.605],[-12.857,-23.249],[-45,-6.641],[-32.144,0.001],[-45,6.645],[-12.857,23.249],[0,16.609],[12.856,23.249],[45,6.645],[32.143,0.001],[45,-6.641]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.9372549019607843,0.9372549019607843,0.9372549019607843,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,55.748],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-16.072,24.171],[16.072,11.312],[16.072,-24.171],[-16.072,-24.171]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.9529411764705882,0.9529411764705882,0.9529411764705882,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[76.072,83.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"ix":3,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-32.143,-24.171],[-32.143,11.311],[-0.001,24.171],[32.144,11.311],[32.144,-24.171]],"c":true}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8,0.82,0.851,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[60,83.33],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"ix":4,"mn":"ADBE Vector Group"},{"ty":"tr","p":{"a":0,"k":[60,60.186],"ix":2},"a":{"a":0,"k":[60,60.186],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"box","np":4,"cix":2,"ix":1,"mn":"ADBE Vector Group"}],"ip":0,"op":50,"st":0,"bm":0,"sr":1}]} ================================================ FILE: simple_live_tv_app/assets/lotties/error.json ================================================ {"v":"5.8.1","fr":29.9700012207031,"ip":0,"op":301.000012259981,"w":1080,"h":900,"nm":"Composition 1","ddd":0,"assets":[{"id":"comp_0","nm":"Nuage","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[54,54],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-22,-239],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[544.675,315.475,0],"ix":2,"l":2},"a":{"a":0,"k":[-54.5,-226.5,0],"ix":1,"l":2},"s":{"a":0,"k":[80,80,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[31,31],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-54.5,-226.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[31,31],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-54.5,-226.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[100,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-26,-216],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_1","nm":"éolienne","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Hélices","refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.137],"y":[1]},"o":{"x":[0.567],"y":[0]},"t":1,"s":[0]},{"t":300.00001221925,"s":[1440]}],"ix":10},"p":{"a":0,"k":[800,440,0],"ix":2,"l":2},"a":{"a":0,"k":[800,440,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Socle eolienne","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[264.75,-95],[257,-95],[242,252],[288,251]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_2","nm":"Hélices","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-239.6,"ix":10},"p":{"a":0,"k":[803,442,0],"ix":2,"l":2},"a":{"a":0,"k":[263,-98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-122.747,"ix":10},"p":{"a":0,"k":[803,442,0],"ix":2,"l":2},"a":{"a":0,"k":[263,-98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[803,442,0],"ix":2,"l":2},"a":{"a":0,"k":[263,-98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[310,-98],[284,-92],[263,-96],[439,10],[423,-17]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[800.5,439.5,0],"ix":2,"l":2},"a":{"a":0,"k":[266.5,-94.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[27,27],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[266.5,-94.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_3","nm":"plot base","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[541,387.5,0],"ix":2,"l":2},"a":{"a":0,"k":[1,-152.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[13,-223],[-13,-223],[-52,-82],[54,-82]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,502,0],"ix":2,"l":2},"a":{"a":0,"k":[0,-38,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[58,-56],[-59,-56],[-70,-20],[70,-20]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[539.75,606.25,0],"ix":2,"l":2},"a":{"a":0,"k":[-0.25,66.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[256.5,28.5],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.7647058823529411,0.3215686274509804,0.23137254901960785,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-0.25,66.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,572,0],"ix":2,"l":2},"a":{"a":0,"k":[0,32,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[78,3],[-76,3],[-93,60],[93,61]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.9019607843137255,0.3764705882352941,0.27058823529411763,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_4","nm":"Tree","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-171.5,-79.5],[-152.5,-45]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980451995,0.84313731474,0.84313731474,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-154.5,-23.5],[-137.5,-48.5]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980451995,0.84313731474,0.84313731474,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[386,620,0],"ix":2,"l":2},"a":{"a":0,"k":[-154,80,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-154,256],[-154,-96]],"c":false},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.850980392157,0.844306078144,0.844306078144,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Contour 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[384,475,0],"ix":2,"l":2},"a":{"a":0,"k":[-156,-65,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[96,222],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":62,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.949019667682,0.949019667682,0.949019667682,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-156,-65],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]},{"id":"comp_5","nm":"ground","fr":29.9700012207031,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Calque de forme 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[515,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[662,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[817,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[78,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Calque de forme 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[752,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[89,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Calque de forme 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[270,795.5,0],"ix":2,"l":2},"a":{"a":0,"k":[-273.5,78,0],"ix":1,"l":2},"s":{"a":0,"k":[102,317,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[59,2],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":2371,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.133333333333,0.145098039216,0.235294132607,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-273.5,78],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Nuage","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":234,"s":[100]},{"t":299.00001217852,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.284,"y":1},"o":{"x":0.387,"y":0},"t":0,"s":[704,380,0],"to":[-36.667,0,0],"ti":[36.667,0,0]},{"t":299.00001217852,"s":[484,380,0]}],"ix":2,"l":2},"a":{"a":0,"k":[514,308,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Calque de forme 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],"o":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],"v":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.83137254902,0.821591725069,0.821591725069,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":0,"nm":"éolienne","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[804,796,0],"ix":2,"l":2},"a":{"a":0,"k":[804,796,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"plot base","refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":7.368,"s":[6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":14.736,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":22.264,"s":[4]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":29.633,"s":[-2]},{"t":37.0000015070409,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[540,792,0],"to":[0,-2.667,0],"ti":[0,2,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":7.368,"s":[540,776,0],"to":[0,-2,0],"ti":[0,-1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":14.736,"s":[540,780,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":22.264,"s":[540,784,0],"to":[0,1.333,0],"ti":[0,-2,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":29.633,"s":[540,788,0],"to":[0,2,0],"ti":[0,-1.333,0]},{"t":37.0000015070409,"s":[540,796,0]}],"ix":2,"l":2},"a":{"a":0,"k":[540,616,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":0,"nm":"éolienne","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[670,796,0],"ix":2,"l":2},"a":{"a":0,"k":[804,796,0],"ix":1,"l":2},"s":{"a":0,"k":[63,63,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":0,"nm":"Tree","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,790,0],"ix":2,"l":2},"a":{"a":0,"k":[384,790,0],"ix":1,"l":2},"s":{"a":0,"k":[82,82,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":0,"nm":"Tree","refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[540,540,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Arbuste","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[68,540,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.5,-0.5],[0,0.5],[0,-1],[0,-0.5],[0,0],[0.5,-0.5],[0,0],[0.5,-0.5],[-0.5,-0.5]],"o":[[-19,-5],[-34,-13],[-18.5,1.5],[-17,10.5],[0,0],[17,-19.5],[6.5,-4],[-3.5,-13],[11.5,-19.5]],"v":[[263.5,176],[242.5,196],[218,213],[209.5,232.5],[215,254.5],[297,253.5],[289.5,225],[294,210],[271.5,204]],"c":true},"ix":2},"nm":"Tracé 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.901960784314,0.901960784314,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Forme 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":0,"nm":"ground","refId":"comp_5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[540,540,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":0,"nm":"Nuage","refId":"comp_0","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":234,"s":[100]},{"t":299.00001217852,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[193,606,0],"to":[56.5,0,0],"ti":[-56.5,0,0]},{"t":299.00001217852,"s":[532,606,0]}],"ix":2,"l":2},"a":{"a":0,"k":[514,308,0],"ix":1,"l":2},"s":{"a":0,"k":[60,60,100],"ix":6,"l":2}},"ao":0,"w":1080,"h":900,"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Calque de forme 6","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[572,712,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[784,628],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Tracé rectangulaire 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.909803921569,0.909803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-36,-234],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Calque de forme 5","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,716,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[728,728],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracé d'ellipse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.976470588235,0.976470588235,0.976470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fond 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8,-140],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transformer "}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":630.000025660426,"st":0,"bm":0},{"ddd":0,"ind":14,"ty":1,"nm":"Blanc uni 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2,"l":2},"a":{"a":0,"k":[540,540,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"sw":1080,"sh":900,"ip":0,"op":630.000025660426,"st":0,"bm":0}],"markers":[]} ================================================ FILE: simple_live_tv_app/assets/lotties/loadding.json ================================================ { "v": "5.5.8", "fr": 50, "ip": 0, "op": 147, "w": 800, "h": 600, "nm": "Paperplane", "ddd": 0, "assets": [ { "id": "comp_0", "layers": [ { "ddd": 0, "ind": 1, "ty": 4, "nm": "planete Outlines - Group 4", "sr": 1, "ks": { "o": { "a": 1, "k": [ { "i": { "x": [ 0.833 ], "y": [ 0.833 ] }, "o": { "x": [ 0.167 ], "y": [ 0.167 ] }, "t": 0, "s": [ 0 ] }, { "i": { "x": [ 0.833 ], "y": [ 0.833 ] }, "o": { "x": [ 0.167 ], "y": [ 0.167 ] }, "t": 38, "s": [ 50 ] }, { "i": { "x": [ 0.833 ], "y": [ 0.833 ] }, "o": { "x": [ 0.167 ], "y": [ 0.167 ] }, "t": 88, "s": [ 50 ] }, { "t": 120, "s": [ 0 ] } ], "ix": 11 }, "r": { "a": 0, "k": 0, "ix": 10 }, "p": { "a": 1, "k": [ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 0, "s": [ 468.336, 323.378, 0 ], "to": [ -29, 0, 0 ], "ti": [ 29, 0, 0 ] }, { "t": 102, "s": [ 294.336, 323.378, 0 ] } ], "ix": 2 }, "a": { "a": 0, "k": [ 453.672, 304.756, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50, 100 ], "ix": 6 } }, "ao": 0, "shapes": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 6.742, 0 ], [ 0.741, -0.14 ], [ 0, 0.074 ], [ 13.484, 0 ], [ 1.669, -0.361 ], [ 19.79, 0 ], [ 3.317, -19.082 ], [ 2.691, 0 ], [ 0, -13.484 ], [ -0.048, -0.629 ], [ 2.405, 0 ], [ 0, -6.742 ], [ -6.742, 0 ], [ 0, 0 ], [ 0, 6.743 ] ], "o": [ [ -0.781, 0 ], [ 0.001, -0.074 ], [ 0, -13.484 ], [ -1.778, 0 ], [ -3.594, -18.742 ], [ -20.03, 0 ], [ -2.421, -0.804 ], [ -13.485, 0 ], [ 0, 0.642 ], [ -1.89, -1.199 ], [ -6.742, 0 ], [ 0, 6.743 ], [ 0, 0 ], [ 6.742, 0 ], [ 0, -6.742 ] ], "v": [ [ 75.134, 16.175 ], [ 72.85, 16.396 ], [ 72.856, 16.175 ], [ 48.44, -8.241 ], [ 43.262, -7.685 ], [ 3.406, -40.591 ], [ -36.571, -6.995 ], [ -44.269, -8.241 ], [ -68.685, 16.175 ], [ -68.604, 18.079 ], [ -75.133, 16.175 ], [ -87.341, 28.383 ], [ -75.133, 40.592 ], [ 75.134, 40.592 ], [ 87.342, 28.383 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.815686334348, 0.823529471603, 0.827451040231, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 453.672, 304.756 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 4", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false } ], "ip": 0, "op": 151, "st": 0, "bm": 0 }, { "ddd": 0, "ind": 2, "ty": 4, "nm": "Merged Shape Layer", "sr": 1, "ks": { "o": { "a": 0, "k": 100, "ix": 11 }, "r": { "a": 1, "k": [ { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.547 ], "y": [ 0 ] }, "t": 0, "s": [ 0 ] }, { "i": { "x": [ 0.845 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 77, "s": [ 35 ] }, { "t": 150, "s": [ 0 ] } ], "ix": 10 }, "p": { "a": 1, "k": [ { "i": { "x": 0.667, "y": 1 }, "o": { "x": 0.333, "y": 0 }, "t": 0, "s": [ 390.319, 298.2, 0 ], "to": [ 0, -2.583, 0 ], "ti": [ 0, 0, 0 ] }, { "i": { "x": 0.667, "y": 1 }, "o": { "x": 0.333, "y": 0 }, "t": 44, "s": [ 390.319, 282.7, 0 ], "to": [ 0, 0, 0 ], "ti": [ 0, 0, 0 ] }, { "i": { "x": 0.667, "y": 1 }, "o": { "x": 0.333, "y": 0 }, "t": 110, "s": [ 390.319, 319.25, 0 ], "to": [ 0, 0, 0 ], "ti": [ 0, 0, 0 ] }, { "t": 150, "s": [ 390.319, 298.2, 0 ] } ], "ix": 2 }, "a": { "a": 0, "k": [ 664.319, 256.2, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100, 100 ], "ix": 6 } }, "ao": 0, "shapes": [ { "ty": "gr", "it": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "o": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "v": [ [ 18.967, -3.189 ], [ -18.967, 19.935 ], [ -0.949, -19.935 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.223528981209, 0.192156970501, 0.674510002136, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 236.879, 292.737 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 1", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 633.939, 275.369 ], "ix": 2 }, "a": { "a": 0, "k": [ 236.879, 292.737 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "planete Outlines - Group 1", "np": 1, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "gr", "it": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "o": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "v": [ [ -98.335, 64.79 ], [ -105.619, 4.984 ], [ 105.619, -64.79 ], [ -80.316, 24.919 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.278430998325, 0.294117987156, 0.847059011459, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 316.247, 247.882 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 2", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 673.623, 252.941 ], "ix": 2 }, "a": { "a": 0, "k": [ 316.247, 247.882 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "planete Outlines - Group 2", "np": 1, "cix": 2, "bm": 0, "ix": 2, "mn": "ADBE Vector Group", "hd": false }, { "ty": "gr", "it": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "o": [ [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ], [ 0, 0 ] ], "v": [ [ -133.812, -42.171 ], [ 133.812, -75.141 ], [ 5.765, 75.141 ], [ -61.708, 18.402 ], [ 124.227, -71.307 ], [ -87.011, -1.534 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.365000009537, 0.407999992371, 0.976000010967, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 297.638, 254.4 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 3", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 664.319, 256.2 ], "ix": 2 }, "a": { "a": 0, "k": [ 297.638, 254.4 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "planete Outlines - Group 3", "np": 1, "cix": 2, "bm": 0, "ix": 3, "mn": "ADBE Vector Group", "hd": false } ], "ip": 0, "op": 151, "st": 0, "bm": 0 }, { "ddd": 0, "ind": 3, "ty": 4, "nm": "planete Outlines - Group 5", "sr": 1, "ks": { "o": { "a": 1, "k": [ { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 0, "s": [ 0 ] }, { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 45, "s": [ 100 ] }, { "i": { "x": [ 0.667 ], "y": [ 1 ] }, "o": { "x": [ 0.333 ], "y": [ 0 ] }, "t": 102, "s": [ 100 ] }, { "t": 150, "s": [ 0 ] } ], "ix": 11 }, "r": { "a": 0, "k": 0, "ix": 10 }, "p": { "a": 1, "k": [ { "i": { "x": 0.833, "y": 0.833 }, "o": { "x": 0.167, "y": 0.167 }, "t": 0, "s": [ 327.38, 267.583, 0 ], "to": [ 25.833, 0, 0 ], "ti": [ -25.833, 0, 0 ] }, { "t": 150, "s": [ 482.38, 267.583, 0 ] } ], "ix": 2 }, "a": { "a": 0, "k": [ 171.76, 193.166, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 50, 50, 100 ], "ix": 6 } }, "ao": 0, "shapes": [ { "ty": "gr", "it": [ { "ind": 0, "ty": "sh", "ix": 1, "ks": { "a": 0, "k": { "i": [ [ 13.485, 0 ], [ 4.38, -4.171 ], [ 21.913, 0 ], [ 3.575, -18.765 ], [ 1.851, 0 ], [ 0, -13.484 ], [ -0.011, -0.291 ], [ 1.599, 0 ], [ 0, -6.743 ], [ -6.742, 0 ], [ 0, 0 ], [ 0, 13.485 ] ], "o": [ [ -6.526, 0 ], [ -0.793, -21.719 ], [ -19.806, 0 ], [ -1.734, -0.391 ], [ -13.485, 0 ], [ 0, 0.293 ], [ -1.4, -0.559 ], [ -6.742, 0 ], [ 0, 6.742 ], [ 0, 0 ], [ 13.485, 0 ], [ 0, -13.484 ] ], "v": [ [ 59.669, -8.242 ], [ 42.84, -1.506 ], [ 2.287, -40.592 ], [ -37.576, -7.638 ], [ -42.962, -8.242 ], [ -67.378, 16.174 ], [ -67.356, 17.049 ], [ -71.878, 16.174 ], [ -84.086, 28.383 ], [ -71.878, 40.591 ], [ 59.669, 40.591 ], [ 84.086, 16.174 ] ], "c": true }, "ix": 2 }, "nm": "Path 1", "mn": "ADBE Vector Shape - Group", "hd": false }, { "ty": "fl", "c": { "a": 0, "k": [ 0.816000007181, 0.823999980852, 0.827000038297, 1 ], "ix": 4 }, "o": { "a": 0, "k": 100, "ix": 5 }, "r": 1, "bm": 0, "nm": "Fill 1", "mn": "ADBE Vector Graphic - Fill", "hd": false }, { "ty": "tr", "p": { "a": 0, "k": [ 171.76, 193.166 ], "ix": 2 }, "a": { "a": 0, "k": [ 0, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 100, 100 ], "ix": 3 }, "r": { "a": 0, "k": 0, "ix": 6 }, "o": { "a": 0, "k": 100, "ix": 7 }, "sk": { "a": 0, "k": 0, "ix": 4 }, "sa": { "a": 0, "k": 0, "ix": 5 }, "nm": "Transform" } ], "nm": "Group 5", "np": 2, "cix": 2, "bm": 0, "ix": 1, "mn": "ADBE Vector Group", "hd": false } ], "ip": 0, "op": 151, "st": 0, "bm": 0 } ] } ], "layers": [ { "ddd": 0, "ind": 1, "ty": 0, "nm": "Pre-comp 1", "refId": "comp_0", "sr": 1, "ks": { "o": { "a": 0, "k": 100, "ix": 11 }, "r": { "a": 0, "k": 0, "ix": 10 }, "p": { "a": 0, "k": [ 406, 306, 0 ], "ix": 2 }, "a": { "a": 0, "k": [ 400, 300, 0 ], "ix": 1 }, "s": { "a": 0, "k": [ 179, 179, 100 ], "ix": 6 } }, "ao": 0, "w": 800, "h": 600, "ip": 0, "op": 147, "st": 0, "bm": 0 } ], "markers": [] } ================================================ FILE: simple_live_tv_app/assets/statement.txt ================================================ 在使用本软件之前,请您仔细阅读以下内容,并确保您充分理解并同意以下条款: 1、本软件为开源软件,您可以免费获取并使用该软件。 2、本软件完全基于您个人意愿使用,您应该对自己的使用行为和所有结果承担全部责任。 3、本软件仅供学习交流、科研等非商业性质的用途,严禁将本软件用于商业目的。如有任何商业行为,均与本软件无关。 4、本软件并不保证与所有操作系统或硬件设备兼容。本软件作者或贡献者不对因使用本软件而产生的任何技术或安全问题承担责任。 5、本软件作者或贡献者不承担因使用本软件而造成的任何直接、间接、特殊或后果性的损失或损害的责任,包括但不限于财产损失、商业利润损失、信息或数据丢失或损坏等。 6、本软件使用者应遵守国家相关法律法规和使用规范,不得利用本软件从事任何违法违规行为。如因使用本软件而导致的违法行为,使用者应承担相应的法律责任。 7、本软件不会收集、存储、使用任何用户的个人信息,包括但不限于姓名、地址、电子邮件地址、电话号码等。在使用本软件过程中,不会进行任何形式的个人信息采集。如用户提供任何个人信息,将被视为用户已自愿提供,并且用户将自行承担由此产生的所有法律责任。 8、本软件作者或贡献者保留随时修改、增加、删除本免责声明中的内容而不另行通知的权利。 9、如果本软件存在侵犯您的合法权益的情况,请及时与作者联系,作者将会及时删除有关内容。 如您不同意本免责声明中的任何内容,请勿使用本软件。使用本软件即代表您已完全理解并同意上述内容。 ================================================ FILE: simple_live_tv_app/lib/app/app_error.dart ================================================ class AppError extends Error { /// 错误码 final int code; /// 错误信息 final String message; /// 是否是Http请求错误 final bool isHttpError; final bool notLogin; AppError( this.message, { this.code = 0, this.isHttpError = false, this.notLogin = false, }); @override String toString() { return message; } } ================================================ FILE: simple_live_tv_app/lib/app/app_focus_node.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; /// 拓展FoucsNode class AppFocusNode extends FocusNode { var isFoucsed = false.obs; AppFocusNode() { isFoucsed.value = hasFocus; addListener(updateFoucs); } updateFoucs() { isFoucsed.value = hasFocus; } @override void dispose() { removeListener(updateFoucs); super.dispose(); } } ================================================ FILE: simple_live_tv_app/lib/app/app_style.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; class AppColors { static ColorScheme lightColorScheme = ColorScheme.fromSwatch( primarySwatch: Colors.pink, brightness: Brightness.dark, //primaryColorDark: const Color(0xfff06595), accentColor: const Color(0xfff06595), ); } class AppStyle { static ThemeData lightTheme = ThemeData( colorScheme: AppColors.lightColorScheme, appBarTheme: const AppBarTheme( elevation: 0, centerTitle: true, ), scaffoldBackgroundColor: const Color(0xfffafafa), radioTheme: RadioThemeData( fillColor: WidgetStateProperty.all(AppColors.lightColorScheme.primary), ), checkboxTheme: CheckboxThemeData( fillColor: WidgetStateProperty.all(AppColors.lightColorScheme.primary), ), fontFamily: Platform.isWindows ? 'Microsoft YaHei' : null, ); static SizedBox get vGap4 => SizedBox( height: 4.w, ); static SizedBox get vGap8 => SizedBox( height: 8.w, ); static SizedBox get vGap12 => SizedBox( height: 12.w, ); static SizedBox get vGap16 => SizedBox( height: 16.w, ); static SizedBox get vGap24 => SizedBox( height: 24.w, ); static SizedBox get vGap32 => SizedBox( height: 32.w, ); static SizedBox get vGap40 => SizedBox( height: 40.w, ); static SizedBox get vGap48 => SizedBox( height: 48.w, ); static SizedBox get hGap4 => SizedBox( width: 4.w, ); static SizedBox get hGap8 => SizedBox( width: 8.w, ); static SizedBox get hGap12 => SizedBox( width: 12.w, ); static SizedBox get hGap16 => SizedBox( width: 16.w, ); static SizedBox get hGap20 => SizedBox( width: 20.w, ); static SizedBox get hGap24 => SizedBox( width: 24.w, ); static SizedBox get hGap32 => SizedBox( width: 32.w, ); static SizedBox get hGap40 => SizedBox( width: 40.w, ); static SizedBox get hGap48 => SizedBox( width: 48.w, ); static EdgeInsets get edgeInsetsH4 => EdgeInsets.symmetric(horizontal: 4.w); static EdgeInsets get edgeInsetsH8 => EdgeInsets.symmetric(horizontal: 8.w); static EdgeInsets get edgeInsetsH12 => EdgeInsets.symmetric(horizontal: 12.w); static EdgeInsets get edgeInsetsH16 => EdgeInsets.symmetric(horizontal: 16.w); static EdgeInsets get edgeInsetsH20 => EdgeInsets.symmetric(horizontal: 20.w); static EdgeInsets get edgeInsetsH24 => EdgeInsets.symmetric(horizontal: 24.w); static EdgeInsets get edgeInsetsH32 => EdgeInsets.symmetric(horizontal: 32.w); static EdgeInsets get edgeInsetsH40 => EdgeInsets.symmetric(horizontal: 40.w); static EdgeInsets get edgeInsetsH48 => EdgeInsets.symmetric(horizontal: 48.w); static EdgeInsets get edgeInsetsV4 => EdgeInsets.symmetric(vertical: 4.w); static EdgeInsets get edgeInsetsV8 => EdgeInsets.symmetric(vertical: 8.w); static EdgeInsets get edgeInsetsV12 => EdgeInsets.symmetric(vertical: 12.w); static EdgeInsets get edgeInsetsV24 => EdgeInsets.symmetric(vertical: 24.w); static EdgeInsets get edgeInsetsV32 => EdgeInsets.symmetric(vertical: 32.w); static EdgeInsets get edgeInsetsV40 => EdgeInsets.symmetric(vertical: 40.w); static EdgeInsets get edgeInsetsV48 => EdgeInsets.symmetric(vertical: 48.w); static EdgeInsets get edgeInsetsA4 => EdgeInsets.all(4.w); static EdgeInsets get edgeInsetsA8 => EdgeInsets.all(8.w); static EdgeInsets get edgeInsetsA12 => EdgeInsets.all(12.w); static EdgeInsets get edgeInsetsA16 => EdgeInsets.all(16.w); static EdgeInsets get edgeInsetsA20 => EdgeInsets.all(20.w); static EdgeInsets get edgeInsetsA24 => EdgeInsets.all(24.w); static EdgeInsets get edgeInsetsA32 => EdgeInsets.all(32.w); static EdgeInsets get edgeInsetsA40 => EdgeInsets.all(40.w); static EdgeInsets get edgeInsetsA48 => EdgeInsets.all(48.w); static EdgeInsets get edgeInsetsR4 => EdgeInsets.only(right: 4.w); static EdgeInsets get edgeInsetsR8 => EdgeInsets.only(right: 8.w); static EdgeInsets get edgeInsetsR12 => EdgeInsets.only(right: 12.w); static EdgeInsets get edgeInsetsR16 => EdgeInsets.only(right: 16.w); static EdgeInsets get edgeInsetsR20 => EdgeInsets.only(right: 20.w); static EdgeInsets get edgeInsetsR24 => EdgeInsets.only(right: 24.w); static EdgeInsets get edgeInsetsL4 => EdgeInsets.only(left: 4.w); static EdgeInsets get edgeInsetsL8 => EdgeInsets.only(left: 8.w); static EdgeInsets get edgeInsetsL12 => EdgeInsets.only(left: 12.w); static EdgeInsets get edgeInsetsL16 => EdgeInsets.only(left: 16.w); static EdgeInsets get edgeInsetsL20 => EdgeInsets.only(left: 20.w); static EdgeInsets get edgeInsetsL24 => EdgeInsets.only(left: 24.w); static EdgeInsets get edgeInsetsT4 => EdgeInsets.only(top: 4.w); static EdgeInsets get edgeInsetsT8 => EdgeInsets.only(top: 8.w); static EdgeInsets get edgeInsetsT12 => EdgeInsets.only(top: 12.w); static EdgeInsets get edgeInsetsT24 => EdgeInsets.only(top: 24.w); static EdgeInsets get edgeInsetsB4 => EdgeInsets.only(bottom: 4.w); static EdgeInsets get edgeInsetsB8 => EdgeInsets.only(bottom: 8.w); static EdgeInsets get edgeInsetsB12 => EdgeInsets.only(bottom: 12.w); static EdgeInsets get edgeInsetsB24 => EdgeInsets.only(bottom: 24.w); static BorderRadius get radius4 => BorderRadius.circular(4.w); static BorderRadius get radius8 => BorderRadius.circular(8.w); static BorderRadius get radius12 => BorderRadius.circular(12.w); static BorderRadius get radius16 => BorderRadius.circular(16.w); static BorderRadius get radius24 => BorderRadius.circular(24.w); static BorderRadius get radius32 => BorderRadius.circular(32.w); static BorderRadius get radius48 => BorderRadius.circular(48.w); static const colorBlack33 = Color(0xff333333); /// 顶部状态栏的高度 static double get statusBarHeight => MediaQuery.of(Get.context!).padding.top; /// 底部导航条的高度 static double get bottomBarHeight => MediaQuery.of(Get.context!).padding.bottom; static TextStyle get titleStyleWhite => TextStyle( color: Colors.white, fontSize: 40.w, ); static TextStyle get titleStyleBlack => TextStyle( color: colorBlack33, fontSize: 40.w, ); static TextStyle get textStyleWhite => TextStyle( color: Colors.white, fontSize: 32.w, ); static TextStyle get textStyleBlack => TextStyle( color: colorBlack33, fontSize: 32.w, ); static TextStyle get subTextStyleWhite => TextStyle( color: Colors.white54, fontSize: 24.w, height: 1.0, ); static TextStyle get subTextStyleBlack => TextStyle( color: Colors.black54, fontSize: 24.w, height: 1.0, ); static List get highlightShadow => [ BoxShadow( blurRadius: 6.w, spreadRadius: 2.w, color: Colors.pink.shade400, //color: Color.fromARGB(255, 255, 120, 167), ) ]; } ================================================ FILE: simple_live_tv_app/lib/app/base_focus_model.dart ================================================ import 'package:simple_live_tv_app/app/app_focus_node.dart'; class BaseFocusModel { final AppFocusNode focusNode = AppFocusNode(); bool get isFoucsed => focusNode.isFoucsed.value; } ================================================ FILE: simple_live_tv_app/lib/app/constant.dart ================================================ import 'package:flutter/material.dart'; class Constant { static const String kUpdateFollow = "UpdateFollow"; static const String kUpdateHistory = "UpdateHistory"; static const String kBiliBili = "bilibili"; static const String kDouyu = "douyu"; static const String kHuya = "huya"; static const String kDouyin = "douyin"; } class HomePageItem { final IconData iconData; final String title; final int index; HomePageItem({ required this.iconData, required this.title, required this.index, }); } ================================================ FILE: simple_live_tv_app/lib/app/controller/app_settings_controller.dart ================================================ import 'package:simple_live_tv_app/services/local_storage_service.dart'; import 'package:get/get.dart'; class AppSettingsController extends GetxController { static AppSettingsController get instance => Get.find(); /// 缩放模式 var scaleMode = 0.obs; var firstRun = false; @override void onInit() { firstRun = LocalStorageService.instance .getValue(LocalStorageService.kFirstRun, true); danmuSize.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuSize, 40.0); danmuOpacity.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuOpacity, 1.0); danmuArea.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuArea, 0.25); danmuSpeed.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuSpeed, 10.0); danmuEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuEnable, true); danmuStrokeWidth.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuStrokeWidth, 4.0); danmuTopMargin.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuTopMargin, 0.0); danmuBottomMargin.value = LocalStorageService.instance .getValue(LocalStorageService.kDanmuBottomMargin, 0.0); hardwareDecode.value = LocalStorageService.instance .getValue(LocalStorageService.kHardwareDecode, true); chatTextSize.value = LocalStorageService.instance .getValue(LocalStorageService.kChatTextSize, 14.0); chatTextGap.value = LocalStorageService.instance .getValue(LocalStorageService.kChatTextGap, 4.0); chatBubbleStyle.value = LocalStorageService.instance.getValue( LocalStorageService.kChatBubbleStyle, false, ); qualityLevel.value = LocalStorageService.instance .getValue(LocalStorageService.kQualityLevel, 1); qualityLevelCellular.value = LocalStorageService.instance .getValue(LocalStorageService.kQualityLevelCellular, 1); autoExitEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoExitEnable, false); autoExitDuration.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoExitDuration, 60); roomAutoExitDuration.value = LocalStorageService.instance .getValue(LocalStorageService.kRoomAutoExitDuration, 60); playerCompatMode.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerCompatMode, true); playerAutoPause.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerAutoPause, false); autoFullScreen.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoFullScreen, false); // ignore: invalid_use_of_protected_member shieldList.value = LocalStorageService.instance.shieldBox.values.toSet(); scaleMode.value = LocalStorageService.instance.getValue( LocalStorageService.kPlayerScaleMode, 0, ); pipHideDanmu.value = LocalStorageService.instance .getValue(LocalStorageService.kPIPHideDanmu, true); styleColor.value = LocalStorageService.instance .getValue(LocalStorageService.kStyleColor, 0xff3498db); isDynamic.value = LocalStorageService.instance .getValue(LocalStorageService.kIsDynamic, false); bilibiliLoginTip.value = LocalStorageService.instance .getValue(LocalStorageService.kBilibiliLoginTip, true); playerBufferSize.value = LocalStorageService.instance .getValue(LocalStorageService.kPlayerBufferSize, 32); autoUpdateFollowEnable.value = LocalStorageService.instance .getValue(LocalStorageService.kAutoUpdateFollowEnable, true); autoUpdateFollowDuration.value = LocalStorageService.instance .getValue(LocalStorageService.kUpdateFollowDuration, 10); updateFollowThreadCount.value = LocalStorageService.instance .getValue(LocalStorageService.kUpdateFollowThreadCount, 4); super.onInit(); } void setNoFirstRun() { LocalStorageService.instance.setValue(LocalStorageService.kFirstRun, false); } var hardwareDecode = true.obs; void setHardwareDecode(bool e) { hardwareDecode.value = e; LocalStorageService.instance .setValue(LocalStorageService.kHardwareDecode, e); } var chatTextSize = 14.0.obs; void setChatTextSize(double e) { chatTextSize.value = e; LocalStorageService.instance.setValue(LocalStorageService.kChatTextSize, e); } var chatTextGap = 4.0.obs; void setChatTextGap(double e) { chatTextGap.value = e; LocalStorageService.instance.setValue(LocalStorageService.kChatTextGap, e); } var chatBubbleStyle = false.obs; void setChatBubbleStyle(bool e) { chatBubbleStyle.value = e; LocalStorageService.instance .setValue(LocalStorageService.kChatBubbleStyle, e); } var danmuSize = 40.0.obs; void setDanmuSize(double e) { danmuSize.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuSize, e); } var danmuSpeed = 10.0.obs; void setDanmuSpeed(double e) { danmuSpeed.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuSpeed, e); } var danmuArea = 0.25.obs; void setDanmuArea(double e) { danmuArea.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuArea, e); } var danmuOpacity = 1.0.obs; void setDanmuOpacity(double e) { danmuOpacity.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuOpacity, e); } var danmuEnable = true.obs; void setDanmuEnable(bool e) { danmuEnable.value = e; LocalStorageService.instance.setValue(LocalStorageService.kDanmuEnable, e); } var danmuStrokeWidth = 4.0.obs; void setDanmuStrokeWidth(double e) { danmuStrokeWidth.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuStrokeWidth, e); } var qualityLevel = 1.obs; void setQualityLevel(int level) { qualityLevel.value = level; LocalStorageService.instance .setValue(LocalStorageService.kQualityLevel, level); } var qualityLevelCellular = 1.obs; void setQualityLevelCellular(int level) { qualityLevelCellular.value = level; LocalStorageService.instance .setValue(LocalStorageService.kQualityLevelCellular, level); } var autoExitEnable = false.obs; void setAutoExitEnable(bool e) { autoExitEnable.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoExitEnable, e); } var autoExitDuration = 60.obs; void setAutoExitDuration(int e) { autoExitDuration.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoExitDuration, e); } var roomAutoExitDuration = 60.obs; void setRoomAutoExitDuration(int e) { roomAutoExitDuration.value = e; LocalStorageService.instance .setValue(LocalStorageService.kRoomAutoExitDuration, e); } var playerCompatMode = false.obs; void setPlayerCompatMode(bool e) { playerCompatMode.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerCompatMode, e); } var playerBufferSize = 32.obs; void setPlayerBufferSize(int e) { playerBufferSize.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerBufferSize, e); } var playerAutoPause = false.obs; void setPlayerAutoPause(bool e) { playerAutoPause.value = e; LocalStorageService.instance .setValue(LocalStorageService.kPlayerAutoPause, e); } var autoFullScreen = false.obs; void setAutoFullScreen(bool e) { autoFullScreen.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoFullScreen, e); } RxSet shieldList = {}.obs; void addShieldList(String e) { shieldList.add(e); LocalStorageService.instance.shieldBox.put(e, e); } void removeShieldList(String e) { shieldList.remove(e); LocalStorageService.instance.shieldBox.delete(e); } Future clearShieldList() async { shieldList.clear(); await LocalStorageService.instance.shieldBox.clear(); } void setScaleMode(int value) { scaleMode.value = value; LocalStorageService.instance.setValue( LocalStorageService.kPlayerScaleMode, value, ); } RxList siteSort = RxList(); void setSiteSort(List e) { siteSort.value = e; LocalStorageService.instance.setValue( LocalStorageService.kSiteSort, siteSort.join(","), ); } RxList homeSort = RxList(); void setHomeSort(List e) { homeSort.value = e; LocalStorageService.instance.setValue( LocalStorageService.kHomeSort, homeSort.join(","), ); } var pipHideDanmu = true.obs; void setPIPHideDanmu(bool e) { pipHideDanmu.value = e; LocalStorageService.instance.setValue(LocalStorageService.kPIPHideDanmu, e); } var styleColor = 0xff3498db.obs; void setStyleColor(int e) { styleColor.value = e; LocalStorageService.instance.setValue(LocalStorageService.kStyleColor, e); } var isDynamic = false.obs; void setIsDynamic(bool e) { isDynamic.value = e; LocalStorageService.instance.setValue(LocalStorageService.kIsDynamic, e); } var danmuTopMargin = 0.0.obs; void setDanmuTopMargin(double e) { danmuTopMargin.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuTopMargin, e); } var danmuBottomMargin = 0.0.obs; void setDanmuBottomMargin(double e) { danmuBottomMargin.value = e; LocalStorageService.instance .setValue(LocalStorageService.kDanmuBottomMargin, e); } var bilibiliLoginTip = true.obs; void setBiliBiliLoginTip(bool e) { bilibiliLoginTip.value = e; LocalStorageService.instance .setValue(LocalStorageService.kBilibiliLoginTip, e); } var autoUpdateFollowEnable = false.obs; void setAutoUpdateFollowEnable(bool e) { autoUpdateFollowEnable.value = e; LocalStorageService.instance .setValue(LocalStorageService.kAutoUpdateFollowEnable, e); } var autoUpdateFollowDuration = 10.obs; void setAutoUpdateFollowDuration(int e) { autoUpdateFollowDuration.value = e; LocalStorageService.instance .setValue(LocalStorageService.kUpdateFollowDuration, e); } var updateFollowThreadCount = 4.obs; void setUpdateFollowThreadCount(int e) { updateFollowThreadCount.value = e; LocalStorageService.instance .setValue(LocalStorageService.kUpdateFollowThreadCount, e); } } ================================================ FILE: simple_live_tv_app/lib/app/controller/base_controller.dart ================================================ import 'dart:async'; import 'package:flutter/widgets.dart'; import 'package:simple_live_tv_app/app/app_error.dart'; import 'package:flutter_easyrefresh/easy_refresh.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; class BaseController extends GetxController { /// 加载中,更新页面 var pageLoadding = false.obs; /// 加载中 var loadding = false.obs; /// 空白页面 var pageEmpty = false.obs; /// 页面错误 var pageError = false.obs; /// 未登录 var notLogin = false.obs; /// 错误信息 var errorMsg = "".obs; /// 显示错误 /// * [msg] 错误信息 /// * [showPageError] 显示页面错误 /// * 只在第一页加载错误时showPageError=true,后续页加载错误时使用Toast弹出通知 void handleError(Object exception, {bool showPageError = false}) { var msg = exceptionToString(exception); if (exception is AppError && exception.notLogin) { notLogin.value = true; pageError.value = false; return; } if (showPageError) { pageError.value = true; errorMsg.value = msg; } else { SmartDialog.showToast(exceptionToString(msg)); } } String exceptionToString(Object exception) { if (exception is AppError) { return exception.toString(); } return exception.toString().replaceAll("Exception:", ""); } void onLogin() {} void onLogout() {} } class BasePageController extends BaseController { final ScrollController scrollController = ScrollController(); final EasyRefreshController easyRefreshController = EasyRefreshController(); int currentPage = 1; int count = 0; int maxPage = 0; int pageSize = 24; var canLoadMore = false.obs; var list = [].obs; Future refreshData() async { currentPage = 1; list.value = []; await loadData(); } Future loadData() async { try { if (loadding.value) return; loadding.value = true; pageError.value = false; pageEmpty.value = false; notLogin.value = false; pageLoadding.value = currentPage == 1; var result = await getData(currentPage, pageSize); //是否可以加载更多 if (result.isNotEmpty) { currentPage++; canLoadMore.value = true; pageEmpty.value = false; } else { canLoadMore.value = false; if (currentPage == 1) { pageEmpty.value = true; } } // 赋值数据 if (currentPage == 1) { list.value = result; } else { list.addAll(result); } } catch (e) { handleError(e, showPageError: currentPage == 1); } finally { loadding.value = false; pageLoadding.value = false; } } Future> getData(int page, int pageSize) async { return []; } void scrollToTopOrRefresh() { if (scrollController.offset > 0) { scrollController.animateTo( 0, duration: const Duration(milliseconds: 200), curve: Curves.linear, ); } else { easyRefreshController.callRefresh(); } } } ================================================ FILE: simple_live_tv_app/lib/app/event_bus.dart ================================================ import 'dart:async'; import 'package:simple_live_tv_app/app/log.dart'; /// 全局事件 class EventBus { static EventBus? _instance; static EventBus get instance { _instance ??= EventBus(); return _instance!; } final Map _streams = {}; /// 触发事件 void emit(String name, T data) { if (!_streams.containsKey(name)) { _streams.addAll({name: StreamController.broadcast()}); } Log.d("Emit Event:$name\r\n$data"); _streams[name]!.add(data); } /// 监听事件 StreamSubscription listen(String name, Function(dynamic)? onData) { if (!_streams.containsKey(name)) { _streams.addAll({name: StreamController.broadcast()}); } return _streams[name]!.stream.listen(onData); } } ================================================ FILE: simple_live_tv_app/lib/app/log.dart ================================================ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:logger/logger.dart'; class Log { static RxList debugLogs = [].obs; static Logger logger = Logger( printer: PrettyPrinter( methodCount: 0, errorMethodCount: 8, lineLength: 120, colors: true, printEmojis: true, dateTimeFormat: DateTimeFormat.none, ), ); static void d(String message) { logger.d("${DateTime.now().toString()}\n$message"); } static void i(String message) { logger.i("${DateTime.now().toString()}\n$message"); } static void e(String message, StackTrace stackTrace) { logger.e("${DateTime.now().toString()}\n$message", stackTrace: stackTrace); } static void w(String message) { logger.w("${DateTime.now().toString()}\n$message"); } static void logPrint(dynamic obj) { //logger.e(obj.toString(), obj, obj?.stackTrace); if (kDebugMode) { print(obj); } } } class DebugLogModel { final String content; final DateTime datetime; final Color? color; DebugLogModel(this.datetime, this.content, {this.color}); } ================================================ FILE: simple_live_tv_app/lib/app/sites.dart ================================================ import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; class Sites { static final Map allSites = { "bilibili": Site( id: "bilibili", logo: "assets/images/bilibili_2.png", name: "哔哩哔哩", liveSite: BiliBiliSite(), index: 0, ), "douyu": Site( id: "douyu", logo: "assets/images/douyu.png", name: "斗鱼直播", liveSite: DouyuSite(), index: 1, ), "huya": Site( id: "huya", logo: "assets/images/huya.png", name: "虎牙直播", liveSite: HuyaSite(), index: 2, ), "douyin": Site( id: "douyin", logo: "assets/images/douyin.png", name: "抖音直播", liveSite: DouyinSite(), index: 3, ), }; static List get supportSites { return allSites.values.toList(); } } class Site { final String id; final String name; final String logo; final LiveSite liveSite; final int index; AppFocusNode appFocusNode = AppFocusNode(); Site({ required this.id, required this.liveSite, required this.logo, required this.name, required this.index, }); } ================================================ FILE: simple_live_tv_app/lib/app/utils.dart ================================================ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:intl/intl.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; class Utils { static late PackageInfo packageInfo; static DateFormat dateFormat = DateFormat("MM-dd HH:mm"); static DateFormat dateFormatWithYear = DateFormat("yyyy-MM-dd HH:mm"); /// 处理时间 static String parseTime(DateTime? dt) { if (dt == null) { return ""; } var dtNow = DateTime.now(); if (dt.year == dtNow.year && dt.month == dtNow.month && dt.day == dtNow.day) { return "${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}"; } if (dt.year == dtNow.year) { return dateFormat.format(dt); } return dateFormatWithYear.format(dt); } /// 提示弹窗 /// - `content` 内容 /// - `title` 弹窗标题 /// - `confirm` 确认按钮内容,留空为确定 /// - `cancel` 取消按钮内容,留空为取消 static Future showAlertDialog( String content, { String title = '', String confirm = '', String cancel = '', bool selectable = false, List? actions, }) async { var result = await Get.dialog( AlertDialog( shape: RoundedRectangleBorder( borderRadius: AppStyle.radius16, ), titlePadding: AppStyle.edgeInsetsA24.copyWith(left: 48.w, right: 48.w), contentPadding: AppStyle.edgeInsetsA24.copyWith(left: 48.w, right: 48.w), insetPadding: AppStyle.edgeInsetsA16, actionsPadding: AppStyle.edgeInsetsA16, surfaceTintColor: Colors.transparent, backgroundColor: Get.theme.cardColor, title: Text( title, style: AppStyle.titleStyleWhite, ), content: Padding( padding: AppStyle.edgeInsetsV12, child: selectable ? SelectableText( content, style: AppStyle.textStyleWhite, ) : Text( content, style: AppStyle.textStyleWhite, ), ), actions: [ TextButton( onPressed: (() => Get.back(result: false)), child: Text( cancel.isEmpty ? "取消" : cancel, style: AppStyle.textStyleWhite, ), ), TextButton( autofocus: true, onPressed: (() => Get.back(result: true)), child: Text( confirm.isEmpty ? "确定" : confirm, style: AppStyle.textStyleWhite, ), ), ...?actions, ], ), ); return result ?? false; } /// 提示弹窗 /// - `content` 内容 /// - `title` 弹窗标题 /// - `confirm` 确认按钮内容,留空为确定 static Future showMessageDialog(String content, {String title = '', String confirm = '', bool selectable = false}) async { var result = await Get.dialog( AlertDialog( title: Text(title), content: Padding( padding: AppStyle.edgeInsetsV12, child: selectable ? SelectableText(content) : Text(content), ), actions: [ TextButton( onPressed: (() => Get.back(result: true)), child: Text(confirm.isEmpty ? "确定" : confirm), ), ], ), ); return result ?? false; } static Future showOptionDialog( List contents, T value, { String title = '', }) async { var result = await Get.dialog( AlertDialog( title: Text(title), content: RadioGroup( onChanged: (e) => Get.back(result: e), groupValue: value, child: Column( children: contents .map( (e) => RadioListTile(title: Text(e.toString()), value: e), ) .toList(), ), ), ), ); return result; } static Future showMapOptionDialog( Map contents, T value, { String title = '', }) async { var result = await Get.dialog( AlertDialog( title: Text(title), content: RadioGroup( onChanged: (e) => Get.back(result: e), groupValue: value, child: Column( children: contents.keys .map( (e) => RadioListTile( title: Text((contents[e] ?? '-').tr), value: e, ), ) .toList(), ), ), ), ); return result; } static bool isRegexFormat(String keyword) { return keyword.startsWith('/') && keyword.endsWith('/') && keyword.length > 2; } static String removeRegexFormat(String keyword) { return keyword.substring(1, keyword.length - 1); } static void showRightDialog({ Function()? onDismiss, required Widget child, double width = 320, bool useSystem = false, }) { SmartDialog.show( alignment: Alignment.topRight, animationBuilder: (controller, child, animationParam) { //从右到左 return SlideTransition( position: Tween( begin: const Offset(1, 0), end: Offset.zero, ).animate(controller.view), child: child, ); }, useSystem: useSystem, maskColor: Colors.transparent, animationTime: const Duration(milliseconds: 200), builder: (context) => Container( width: width, decoration: BoxDecoration( color: Get.theme.cardColor, ), child: child, ), ); } static Future showSystemRightDialog({ Function()? onDismiss, required Widget child, double width = 320, }) { return Get.dialog( Dialog( insetPadding: EdgeInsets.zero, backgroundColor: Colors.transparent, child: Align( alignment: Alignment.topRight, child: Container( width: width, decoration: BoxDecoration( color: Get.theme.cardColor, ), child: child, ), ), ), ); } static void hideRightDialog() { SmartDialog.dismiss(status: SmartStatus.allCustom); } static int parseVersion(String version) { var sp = version.split('.'); var num = ""; for (var item in sp) { num = num + item.padLeft(2, '0'); } return int.parse(num); } static String onlineToString(int num) { if (num >= 10000) { return "${(num / 10000.0).toStringAsFixed(1)}万"; } return num.toString(); } } ================================================ FILE: simple_live_tv_app/lib/main.dart ================================================ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:logger/logger.dart'; import 'package:media_kit/media_kit.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/models/db/follow_user.dart'; import 'package:simple_live_tv_app/models/db/history.dart'; import 'package:simple_live_tv_app/routes/app_pages.dart'; import 'package:simple_live_tv_app/routes/route_path.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; import 'package:simple_live_tv_app/services/db_service.dart'; import 'package:simple_live_tv_app/services/follow_user_service.dart'; import 'package:simple_live_tv_app/services/local_storage_service.dart'; import 'package:simple_live_tv_app/services/sync_service.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); MediaKit.ensureInitialized(); await Hive.initFlutter(); //初始化服务 await initServices(); // 强制横屏 SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeRight, DeviceOrientation.landscapeLeft, ]); // 全屏 SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []); runApp(const MyApp()); } Future initServices() async { //日志信息 CoreLog.enableLog = !kReleaseMode; CoreLog.requestLogType = RequestLogType.short; CoreLog.onPrintLog = (level, msg) { switch (level) { case Level.debug: Log.d(msg); break; case Level.error: Log.e(msg, StackTrace.current); break; case Level.info: Log.i(msg); break; case Level.warning: Log.w(msg); break; default: Log.logPrint(msg); } }; Hive.registerAdapter(FollowUserAdapter()); Hive.registerAdapter(HistoryAdapter()); //包信息 Utils.packageInfo = await PackageInfo.fromPlatform(); //本地存储 Log.d("Init LocalStorage Service"); await Get.put(LocalStorageService()).init(); await Get.put(DBService()).init(); //初始化设置控制器 Get.put(AppSettingsController()); Get.put(BiliBiliAccountService()); Get.put(SyncService()); Get.put(FollowUserService()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return ScreenUtilInit( designSize: const Size(1920, 1080), minTextAdapt: true, splitScreenMode: true, builder: (context, child) { return GetMaterialApp( title: 'Simple Live TV', theme: AppStyle.lightTheme, initialRoute: AppSettingsController.instance.firstRun ? RoutePath.kAgreement : RoutePath.kHome, getPages: AppPages.routes, debugShowCheckedModeBanner: false, builder: FlutterSmartDialog.init( loadingBuilder: (msg) => Center( child: SizedBox( width: 64.w, height: 64.w, child: CircularProgressIndicator( strokeWidth: 8.w, color: Colors.white, ), ), ), //字体大小不跟随系统变化 builder: (context, child) => MediaQuery( data: MediaQuery.of(context).copyWith( textScaler: const TextScaler.linear(1.0), ), child: child!, ), ), ); }, ); } } ================================================ FILE: simple_live_tv_app/lib/models/account/bilibili_user_info_page.dart ================================================ import 'dart:convert'; T? asT(dynamic value) { if (value is T) { return value; } return null; } class BiliBiliUserInfoModel { BiliBiliUserInfoModel({ this.mid, this.uname, this.userid, this.sign, this.birthday, this.sex, this.nickFree, this.rank, }); factory BiliBiliUserInfoModel.fromJson(Map json) => BiliBiliUserInfoModel( mid: asT(json['mid']), uname: asT(json['uname']), userid: asT(json['userid']), sign: asT(json['sign']), birthday: asT(json['birthday']), sex: asT(json['sex']), nickFree: asT(json['nick_free']), rank: asT(json['rank']), ); int? mid; String? uname; String? userid; String? sign; String? birthday; String? sex; bool? nickFree; String? rank; @override String toString() { return jsonEncode(this); } Map toJson() => { 'mid': mid, 'uname': uname, 'userid': userid, 'sign': sign, 'birthday': birthday, 'sex': sex, 'nick_free': nickFree, 'rank': rank, }; } ================================================ FILE: simple_live_tv_app/lib/models/db/follow_user.dart ================================================ import 'package:get/get.dart'; import 'package:hive/hive.dart'; part 'follow_user.g.dart'; @HiveType(typeId: 1) class FollowUser { FollowUser({ required this.id, required this.roomId, required this.siteId, required this.userName, required this.face, required this.addTime, }); ///id=siteId_roomId @HiveField(0) String id; @HiveField(1) String roomId; @HiveField(2) String siteId; @HiveField(3) String userName; @HiveField(4) String face; @HiveField(5) DateTime addTime; /// 直播状态 /// 0=未知(加载中) 1=未开播 2=直播中 Rx liveStatus = 0.obs; factory FollowUser.fromJson(Map json) => FollowUser( id: json['id'], roomId: json['roomId'], siteId: json['siteId'], userName: json['userName'], face: json['face'], addTime: DateTime.parse(json['addTime']), ); Map toJson() => { 'id': id, 'roomId': roomId, 'siteId': siteId, 'userName': userName, 'face': face, 'addTime': addTime.toString(), }; } ================================================ FILE: simple_live_tv_app/lib/models/db/follow_user.g.dart ================================================ // GENERATED CODE - DO NOT MODIFY BY HAND part of 'follow_user.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** class FollowUserAdapter extends TypeAdapter { @override final int typeId = 1; @override FollowUser read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return FollowUser( id: fields[0] as String, roomId: fields[1] as String, siteId: fields[2] as String, userName: fields[3] as String, face: fields[4] as String, addTime: fields[5] as DateTime, ); } @override void write(BinaryWriter writer, FollowUser obj) { writer ..writeByte(6) ..writeByte(0) ..write(obj.id) ..writeByte(1) ..write(obj.roomId) ..writeByte(2) ..write(obj.siteId) ..writeByte(3) ..write(obj.userName) ..writeByte(4) ..write(obj.face) ..writeByte(5) ..write(obj.addTime); } @override int get hashCode => typeId.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is FollowUserAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } ================================================ FILE: simple_live_tv_app/lib/models/db/history.dart ================================================ import 'package:hive/hive.dart'; part 'history.g.dart'; @HiveType(typeId: 2) class History { History({ required this.id, required this.roomId, required this.siteId, required this.userName, required this.face, required this.updateTime, }); ///id=siteId_roomId @HiveField(0) String id; @HiveField(1) String roomId; @HiveField(2) String siteId; @HiveField(3) String userName; @HiveField(4) String face; @HiveField(5) DateTime updateTime; factory History.fromJson(Map json) => History( id: json["id"], roomId: json["roomId"], siteId: json["siteId"], userName: json["userName"], face: json["face"], updateTime: DateTime.parse(json["updateTime"]), ); Map toJson() => { "id": id, "roomId": roomId, "siteId": siteId, "userName": userName, "face": face, "updateTime": updateTime.toString(), }; } ================================================ FILE: simple_live_tv_app/lib/models/db/history.g.dart ================================================ // GENERATED CODE - DO NOT MODIFY BY HAND part of 'history.dart'; // ************************************************************************** // TypeAdapterGenerator // ************************************************************************** class HistoryAdapter extends TypeAdapter { @override final int typeId = 2; @override History read(BinaryReader reader) { final numOfFields = reader.readByte(); final fields = { for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), }; return History( id: fields[0] as String, roomId: fields[1] as String, siteId: fields[2] as String, userName: fields[3] as String, face: fields[4] as String, updateTime: fields[5] as DateTime, ); } @override void write(BinaryWriter writer, History obj) { writer ..writeByte(6) ..writeByte(0) ..write(obj.id) ..writeByte(1) ..write(obj.roomId) ..writeByte(2) ..write(obj.siteId) ..writeByte(3) ..write(obj.userName) ..writeByte(4) ..write(obj.face) ..writeByte(5) ..write(obj.updateTime); } @override int get hashCode => typeId.hashCode; @override bool operator ==(Object other) => identical(this, other) || other is HistoryAdapter && runtimeType == other.runtimeType && typeId == other.typeId; } ================================================ FILE: simple_live_tv_app/lib/models/follow_user_item.dart ================================================ ================================================ FILE: simple_live_tv_app/lib/models/version_model.dart ================================================ import 'dart:convert'; T? asT(dynamic value) { if (value is T) { return value; } return null; } class VersionModel { VersionModel({ required this.version, required this.versionNum, required this.versionDesc, required this.downloadUrl, }); factory VersionModel.fromJson(Map json) => VersionModel( version: asT(json['version'])!, versionNum: asT(json['version_num'])!, versionDesc: asT(json['version_desc'])!, downloadUrl: asT(json['download_url'])!, ); String version; int versionNum; String versionDesc; String downloadUrl; @override String toString() { return jsonEncode(this); } Map toJson() => { 'version': version, 'version_num': versionNum, 'version_desc': versionDesc, 'download_url': downloadUrl, }; } ================================================ FILE: simple_live_tv_app/lib/modules/account/bilibili/qr_login_controller.dart ================================================ import 'dart:async'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/requests/http_client.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; enum QRStatus { loading, unscanned, scanned, expired, failed, } class BiliBiliQRLoginController extends GetxController { @override void onInit() { loadQRCode(); super.onInit(); } Timer? timer; var qrcodeUrl = "".obs; var qrcodeKey = ""; /// 二维码状态 /// - [0] 加载中 /// - [1] 未扫描 /// - [2] 已扫描,待确认 /// - [3] 二维码已经失效 /// - [4] 登录失败 Rx qrStatus = QRStatus.loading.obs; void loadQRCode() async { try { qrStatus.value = QRStatus.loading; var result = await HttpClient.instance.getJson( "https://passport.bilibili.com/x/passport-login/web/qrcode/generate", ); if (result["code"] != 0) { throw result["message"]; } qrcodeKey = result["data"]["qrcode_key"]; qrcodeUrl.value = result["data"]["url"]; qrStatus.value = QRStatus.unscanned; startPoll(); } catch (e) { Log.logPrint(e); SmartDialog.showToast(e.toString()); qrStatus.value = QRStatus.failed; } } void startPoll() { timer = Timer.periodic( const Duration(seconds: 3), (timer) { pollQRStatus(); }, ); } void pollQRStatus() async { try { var response = await HttpClient.instance.get( "https://passport.bilibili.com/x/passport-login/web/qrcode/poll", queryParameters: { "qrcode_key": qrcodeKey, }, ); if (response.data["code"] != 0) { throw response.data["message"]; } var data = response.data["data"]; var code = data["code"]; if (code == 0) { var cookies = []; response.headers["set-cookie"]?.forEach((element) { var cookie = element.split(";")[0]; cookies.add(cookie); }); if (cookies.isNotEmpty) { var cookieStr = cookies.join(";"); Log.i(cookieStr); BiliBiliAccountService.instance.setCookie(cookieStr); await BiliBiliAccountService.instance.loadUserInfo(); Get.back(); } } else if (code == 86038) { qrStatus.value = QRStatus.expired; qrcodeKey = ""; timer?.cancel(); } else if (code == 86090) { qrStatus.value = QRStatus.scanned; } } catch (e) { Log.logPrint(e); SmartDialog.showToast(e.toString()); } } @override void onClose() { timer?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/modules/account/bilibili/qr_login_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/modules/account/bilibili/qr_login_controller.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; class BiliBiliQRLoginPage extends GetView { const BiliBiliQRLoginPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "登录哔哩哔哩", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), ], ), AppStyle.vGap48, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Obx( () { if (controller.qrStatus.value == QRStatus.loading) { return SizedBox( width: 64.w, height: 64.w, child: CircularProgressIndicator( strokeWidth: 8.w, color: Colors.white, ), ); } if (controller.qrStatus.value == QRStatus.failed) { return Column( mainAxisSize: MainAxisSize.min, children: [ Text( "二维码加载失败", style: AppStyle.textStyleWhite, ), HighlightButton( focusNode: AppFocusNode(), iconData: Icons.refresh, text: "重试", onTap: controller.loadQRCode, ), ], ); } if (controller.qrStatus.value == QRStatus.failed) { return Column( mainAxisSize: MainAxisSize.min, children: [ Text( "二维码已失效", style: AppStyle.textStyleWhite, ), HighlightButton( focusNode: AppFocusNode(), iconData: Icons.refresh, text: "刷新", onTap: controller.loadQRCode, ), ], ); } return Column( children: [ ClipRRect( borderRadius: AppStyle.radius12, child: QrImageView( data: controller.qrcodeUrl.value, version: QrVersions.auto, backgroundColor: Colors.white, size: 360.w, padding: AppStyle.edgeInsetsA12, ), ), AppStyle.vGap8, Visibility( visible: controller.qrStatus.value == QRStatus.scanned, child: Text( "已扫描,请在手机上确认登录", style: AppStyle.textStyleWhite, ), ), ], ); }, ), ), Padding( padding: AppStyle.edgeInsetsA24, child: Text( "请使用哔哩哔哩手机客户端扫描二维码登录\n必须登录后才能观看哔哩哔哩直播", textAlign: TextAlign.center, style: TextStyle(fontSize: 32.w), ), ), ], ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/agreement/agreement_page.dart ================================================ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/routes/route_path.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; class AgreementPage extends StatelessWidget { const AgreementPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Center( child: SizedBox( width: 1000.w, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( "使用须知", textAlign: TextAlign.center, style: AppStyle.titleStyleWhite, ), AppStyle.vGap24, Text( "欢迎使用Simple Live TV,请在使用前仔细阅读以下内容:", style: AppStyle.textStyleWhite, ), AppStyle.vGap12, Text( "1. 本软件为开源软件,仅供学习交流使用,禁止用于任何商业用途。", style: AppStyle.textStyleWhite, ), AppStyle.vGap12, Text( "2. 本软件不提供任何直播内容,所有直播内容均来自网络。", style: AppStyle.textStyleWhite, ), AppStyle.vGap12, Text( "3. 本软件完全基于您个人意愿使用,您应该对自己的使用行为和所有结果承担全部责任。", style: AppStyle.textStyleWhite, ), AppStyle.vGap12, Text( "4. 如果本软件存在侵犯您的合法权益的情况,请及时与作者联系,作者将会及时删除有关内容。", style: AppStyle.textStyleWhite, ), AppStyle.vGap12, Text( "如您继续使用本软件即代表您已完全理解并同意上述内容。", style: AppStyle.textStyleWhite, ), AppStyle.vGap32, Row( mainAxisAlignment: MainAxisAlignment.center, children: [ HighlightButton( text: "已阅读并同意", autofocus: true, focusNode: AppFocusNode(), onTap: () { AppSettingsController.instance.setNoFirstRun(); Get.offAllNamed(RoutePath.kHome); }, ), AppStyle.hGap32, HighlightButton( text: "退出应用", focusNode: AppFocusNode(), onTap: () { //退出软件 exit(0); }, ), ], ) ], ), ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/category/category_controller.dart ================================================ import 'package:get/get.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; class CategoryController extends BasePageController { var siteId = Constant.kBiliBili.obs; var site = Sites.allSites[Constant.kBiliBili]!; @override void onInit() { refreshData(); super.onInit(); } void setSite(String id) { siteId.value = id; site = Sites.allSites[id]!; refreshData(); } @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.getCategores(); return result.map((e) => AppLiveCategory.fromLiveCategory(e)).toList(); } } class AppLiveCategory extends LiveCategory { var showAll = false.obs; final List childrenExt; AppLiveCategory({ required super.id, required super.name, required super.children, }) : childrenExt = children .map((e) => LiveSubCategoryExt( id: e.id, name: e.name, parentId: e.parentId, pic: e.pic, )) .toList() { showAll.value = children.length < 19; } List get take15 => childrenExt.take(15).toList(); AppFocusNode moreFocusNode = AppFocusNode(); factory AppLiveCategory.fromLiveCategory(LiveCategory item) { return AppLiveCategory( children: item.children, id: item.id, name: item.name, ); } } class LiveSubCategoryExt extends LiveSubCategory { LiveSubCategoryExt({ required super.id, required super.name, required super.parentId, super.pic, }); AppFocusNode focusNode = AppFocusNode(); } ================================================ FILE: simple_live_tv_app/lib/modules/category/category_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; import 'package:simple_live_tv_app/widgets/net_image.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/category/category_controller.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; class CategoryPage extends GetView { const CategoryPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "直播类目", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), Obx( () => Visibility( visible: controller.loadding.value, child: SizedBox( width: 48.w, height: 48.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 4.w, ), ), ), ), // AppStyle.hGap24, // HighlightButton( // focusNode: AppFocusNode(), // iconData: Icons.refresh, // text: "刷新", // onTap: () { // controller.refreshData(); // }, // ), AppStyle.hGap48, ], ), AppStyle.vGap24, Wrap( alignment: WrapAlignment.center, spacing: 36.w, children: Sites.supportSites .map( (e) => Obx( () => HighlightButton( icon: Image.asset( e.logo, width: 48.w, height: 48.w, ), text: e.name, selected: controller.siteId.value == e.id, focusNode: AppFocusNode(), onTap: () { controller.setSite(e.id); }, ), ), ) .toList(), ), AppStyle.vGap24, Expanded( child: Obx( () => ListView.builder( padding: AppStyle.edgeInsetsH48, itemCount: controller.list.length, controller: controller.scrollController, itemBuilder: (_, i) { var item = controller.list[i]; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Padding( padding: AppStyle.edgeInsetsV32, child: Text( item.name, style: AppStyle.titleStyleWhite, ), ), Obx( () => GridView.count( shrinkWrap: true, padding: AppStyle.edgeInsetsV8, physics: const NeverScrollableScrollPhysics(), crossAxisCount: 8, crossAxisSpacing: 36.w, mainAxisSpacing: 36.w, children: item.showAll.value ? (item.childrenExt .map( (e) => buildSubCategory(e), ) .toList()) : (item.take15 .map( (e) => buildSubCategory(e), ) .toList() ..add(buildShowMore(item))), ), ), ], ); }, ), ), ), ], ), ); } Widget buildSubCategory(LiveSubCategoryExt item) { return HighlightWidget( focusNode: item.focusNode, onTap: () { AppNavigator.toCategoryDetail(site: controller.site, category: item); }, color: Colors.white10, borderRadius: AppStyle.radius16, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ (item.pic != null && item.pic!.isNotEmpty) ? NetImage( item.pic ?? "", width: 64.w, height: 64.w, borderRadius: 16.w, cacheWidth: 100, ) : Image.asset( "assets/images/${controller.site.id}.png", width: 64.w, height: 64.w, ), AppStyle.vGap12, Text( item.name, maxLines: 1, textAlign: TextAlign.center, style: item.focusNode.isFoucsed.value ? AppStyle.textStyleBlack : AppStyle.textStyleWhite, ), ], ), ); } Widget buildShowMore(AppLiveCategory item) { return HighlightWidget( focusNode: item.moreFocusNode, onTap: () { item.showAll.value = true; }, color: Colors.white10, borderRadius: AppStyle.radius16, child: Center( child: Text( "显示全部", maxLines: 1, textAlign: TextAlign.center, style: item.moreFocusNode.isFoucsed.value ? AppStyle.textStyleBlack : AppStyle.textStyleWhite, ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/category/detail/category_detail_controller.dart ================================================ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/category/category_controller.dart'; import 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart'; class CategoryDetailController extends BasePageController { final Site site; final LiveSubCategoryExt subCategory; CategoryDetailController({ required this.site, required this.subCategory, }); @override void onInit() { scrollController.addListener(scrollListener); refreshData(); super.onInit(); } void scrollListener() { if (scrollController.position.pixels >= (scrollController.position.maxScrollExtent - 100.w)) { loadData(); } } @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.getCategoryRooms(subCategory, page: page); return result.items .map( (e) => LiveRoomItemExt( roomId: e.roomId, title: e.title, cover: e.cover, userName: e.userName, online: e.online, ), ) .toList(); } @override void onClose() { scrollController.removeListener(scrollListener); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/modules/category/detail/category_detail_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/modules/category/detail/category_detail_controller.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/live_room_card.dart'; class CategoryDetailPage extends GetView { const CategoryDetailPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( controller.subCategory.name, style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), Obx( () => Visibility( visible: controller.loadding.value, child: SizedBox( width: 48.w, height: 48.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 4.w, ), ), ), ), //AppStyle.hGap24, // HighlightButton( // focusNode: AppFocusNode(), // iconData: Icons.refresh, // text: "刷新", // onTap: () { // controller.refreshData(); // }, // ), AppStyle.hGap48, ], ), AppStyle.vGap24, Expanded( child: Obx( () => MasonryGridView.count( padding: AppStyle.edgeInsetsA48, itemCount: controller.list.length, crossAxisCount: 5, crossAxisSpacing: 48.w, mainAxisSpacing: 40.w, controller: controller.scrollController, itemBuilder: (_, i) { var item = controller.list[i]; if (i == 0) { Future.delayed(Duration.zero, () { if (controller.currentPage == 2) { item.focusNode.requestFocus(); } }); } return LiveRoomCard( cover: item.cover, anchor: item.userName, title: item.title, focusNode: item.focusNode, roomId: item.roomId, online: item.online, onTap: () { AppNavigator.toLiveRoomDetail( site: controller.site, roomId: item.roomId, ); }, ); }, ), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/follow_user/follow_user_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/services/follow_user_service.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/anchor_card.dart'; class FollowUserPage extends StatelessWidget { const FollowUserPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "我的关注", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), HighlightButton( focusNode: AppFocusNode(), iconData: Icons.refresh, text: "刷新", onTap: () { FollowUserService.instance.refreshData(); }, ), AppStyle.hGap48, ], ), AppStyle.vGap48, Expanded( child: Obx( () => MasonryGridView.count( padding: AppStyle.edgeInsetsH48, itemCount: FollowUserService.instance.list.length, crossAxisCount: 3, crossAxisSpacing: 48.w, mainAxisSpacing: 40.w, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (_, i) { var item = FollowUserService.instance.list[i]; return AnchorCard( face: item.face, name: item.userName, siteId: item.siteId, liveStatus: item.liveStatus.value, roomId: item.roomId, ); }, ), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/history/history_controller.dart ================================================ import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/models/db/history.dart'; import 'package:simple_live_tv_app/services/db_service.dart'; class HistoryController extends BasePageController { @override void onInit() { refreshData(); super.onInit(); } @override Future> getData(int page, int pageSize) { if (page > 1) { return Future.value([]); } return Future.value(DBService.instance.getHistores()); } void clean() async { var result = await Utils.showAlertDialog("确定要清空观看记录吗?", title: "清空观看记录"); if (!result) { return; } await DBService.instance.historyBox.clear(); refreshData(); } void removeItem(History item) async { var result = await Utils.showAlertDialog("确定要删除此记录吗?", title: "删除记录"); if (!result) { return; } await DBService.instance.historyBox.delete(item.id); refreshData(); } } ================================================ FILE: simple_live_tv_app/lib/modules/history/history_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/modules/history/history_controller.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/anchor_card.dart'; class HistoryPage extends GetView { const HistoryPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "观看记录", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), HighlightButton( focusNode: AppFocusNode(), iconData: Icons.delete_outline_rounded, text: "清空", onTap: () { controller.clean(); }, ), AppStyle.hGap48, ], ), AppStyle.vGap48, Expanded( child: Obx( () => MasonryGridView.count( padding: AppStyle.edgeInsetsH48, itemCount: controller.list.length, crossAxisCount: 3, crossAxisSpacing: 48.w, mainAxisSpacing: 40.w, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (_, i) { var item = controller.list[i]; return AnchorCard( face: item.face, name: item.userName, siteId: item.siteId, liveStatus: 0, roomId: item.roomId, ); }, ), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/home/home_controller.dart ================================================ import 'dart:async'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/routes/route_path.dart'; class HomeController extends BaseController { var datetime = "00:00".obs; @override void onInit() { initTimer(); super.onInit(); } void initTimer() { Timer.periodic(const Duration(seconds: 1), (timer) { var now = DateTime.now(); datetime.value = "${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}"; }); } void toSync() { Get.toNamed(RoutePath.kSync); } void toFollow() { Get.toNamed(RoutePath.kFollow); } void toSettings() { Get.toNamed(RoutePath.kSettings); } void toHistory() { Get.toNamed(RoutePath.kHistory); } void toHotLive() { Get.toNamed(RoutePath.kHotLive); } void toSearchRoom(String keyword) { Get.toNamed(RoutePath.kSearchRoom, arguments: keyword); } void toSearchAnchor(String keyword) { Get.toNamed(RoutePath.kSearchAnchor, arguments: keyword); } void toCategory() { Get.toNamed(RoutePath.kCategory); } } ================================================ FILE: simple_live_tv_app/lib/modules/home/home_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:lottie/lottie.dart'; import 'package:remixicon/remixicon.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/modules/home/home_controller.dart'; import 'package:simple_live_tv_app/services/follow_user_service.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_list_tile.dart'; import 'package:simple_live_tv_app/widgets/card/anchor_card.dart'; import 'package:simple_live_tv_app/widgets/button/home_big_button.dart'; import 'package:simple_live_tv_app/widgets/net_image.dart'; import 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart'; class HomePage extends GetView { const HomePage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, Text( "Simple Live TV", style: AppStyle.titleStyleWhite, ), AppStyle.hGap24, const Spacer(), Obx( () => Text( controller.datetime.value, style: AppStyle.titleStyleWhite.copyWith(fontSize: 36.w), ), ), AppStyle.hGap32, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.settings, text: "设置", onTap: () { controller.toSettings(); }, ), AppStyle.hGap48, ], ), Expanded( child: ListView( padding: AppStyle.edgeInsetsV32, children: [ Padding( padding: AppStyle.edgeInsetsH48, child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: HomeBigButton( autofocus: true, focusNode: AppFocusNode(), text: "热门直播", iconData: Remix.fire_line, onTap: controller.toHotLive, ), ), AppStyle.hGap48, Expanded( child: HomeBigButton( autofocus: true, focusNode: AppFocusNode(), text: "直播类目", iconData: Remix.apps_line, onTap: controller.toCategory, ), ), AppStyle.hGap48, Expanded( child: HomeBigButton( autofocus: true, focusNode: AppFocusNode(), text: "搜索直播", iconData: Remix.search_2_line, onTap: showSearchDialog, ), ), // AppStyle.hGap40, // Expanded( // child: HomeBigButton( // focusNode: AppFocusNode(), // text: "我的关注", // iconData: Icons.favorite_border, // onTap: controller.toFollow, // ), // ), AppStyle.hGap48, Expanded( child: HomeBigButton( focusNode: AppFocusNode(), text: "观看记录", iconData: Icons.history, onTap: controller.toHistory, ), ), AppStyle.hGap48, Expanded( child: HomeBigButton( focusNode: AppFocusNode(), text: "数据同步", iconData: Icons.devices, onTap: controller.toSync, ), ), ], ), ), AppStyle.vGap32, Padding( padding: AppStyle.edgeInsetsH48, child: Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( width: 64.w, height: 64.w, child: Center( child: Icon( Icons.favorite_border, color: Colors.white, size: 56.w, ), ), ), AppStyle.hGap24, Expanded( child: Text( "我的关注", style: AppStyle.titleStyleWhite, ), ), Obx( () => Visibility( visible: FollowUserService.instance.updating.value, child: Row( children: [ SizedBox( width: 48.w, height: 48.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 4.w, ), ), AppStyle.hGap16, Text( "更新状态中...", style: AppStyle.textStyleWhite, ), ], ), ), ), AppStyle.hGap16, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.settings, text: "管理", onTap: showManageDialog, ), AppStyle.hGap32, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.refresh, text: "刷新", onTap: () { FollowUserService.instance.refreshData(); }, ), ], ), ), AppStyle.vGap32, Obx( () => MasonryGridView.count( padding: AppStyle.edgeInsetsH48, itemCount: FollowUserService.instance.list.length, crossAxisCount: 3, crossAxisSpacing: 48.w, mainAxisSpacing: 48.w, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (_, i) { var item = FollowUserService.instance.list[i]; return Obx( () => AnchorCard( face: item.face, name: item.userName, siteId: item.siteId, liveStatus: item.liveStatus.value, roomId: item.roomId, ), ); }, ), ), Obx( () => Visibility( visible: FollowUserService.instance.list.isEmpty, child: Column( children: [ AppStyle.vGap24, LottieBuilder.asset( 'assets/lotties/empty.json', width: 160.w, height: 160.w, repeat: false, ), AppStyle.vGap24, Text( "暂无任何关注\n您可以从其他端同步数据到此处", textAlign: TextAlign.center, style: AppStyle.textStyleWhite, ), AppStyle.vGap16, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.devices, text: "同步数据", onTap: () { controller.toSync(); }, ), ], ), ), ) ], ), ), ], ), ); } void showManageDialog() { Utils.showSystemRightDialog( //useSystem: true, width: 700.w, child: Column( children: [ AppStyle.vGap24, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", onTap: () { //Utils.hideRightDialog(); Get.back(); }, ), AppStyle.hGap32, Text( "关注管理", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), ], ), Expanded( child: Stack( children: [ Obx( () => ListView.separated( itemCount: FollowUserService.instance.list.length, separatorBuilder: (_, __) => AppStyle.vGap24, padding: AppStyle.edgeInsetsA40, itemBuilder: (_, i) { var item = FollowUserService.instance.list[i]; var foucsNode = AppFocusNode(); return HighlightListTile( autofocus: i == 0, leading: NetImage( item.face, width: 64.w, height: 64.w, borderRadius: 64.w, ), title: item.userName, focusNode: foucsNode, trailing: Obx( () => Icon( Icons.delete_outline_outlined, size: 40.w, color: foucsNode.isFoucsed.value ? Colors.black : Colors.white, ), ), onTap: () { FollowUserService.instance .removeItem(item, refresh: false); }, ); }, ), ), Obx( () => Visibility( visible: FollowUserService.instance.list.isEmpty, child: const AppEmptyWidget( text: "关注列表为空,快去关注一些主播吧", ), ), ), ], ), ), ], ), ); } void showSearchDialog() { var textController = TextEditingController(); var mode = 0.obs; var roomFocusNode = AppFocusNode()..isFoucsed.value = true; var anchorFocusNode = AppFocusNode(); showDialog( context: Get.context!, builder: (_) => AlertDialog( backgroundColor: Get.theme.cardColor, surfaceTintColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: AppStyle.radius16, ), contentPadding: AppStyle.edgeInsetsA48, content: Column( mainAxisSize: MainAxisSize.min, children: [ Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Obx( () => HighlightButton( text: "直播间", iconData: Icons.live_tv, selected: mode.value == 0, focusNode: roomFocusNode, autofocus: roomFocusNode.isFoucsed.value, onTap: () { mode.value = 0; }, ), ), AppStyle.hGap40, Obx( () => HighlightButton( text: "主播", selected: mode.value == 1, iconData: Icons.person, focusNode: anchorFocusNode, autofocus: anchorFocusNode.isFoucsed.value, onTap: () { mode.value = 1; }, ), ), ], ), AppStyle.vGap48, SizedBox( width: 700.w, child: TextField( controller: textController, style: AppStyle.textStyleWhite, textInputAction: TextInputAction.search, onSubmitted: (e) { Get.back(); if (e.isEmpty) { return; } if (mode.value == 0) { controller.toSearchRoom(textController.text); } else { controller.toSearchAnchor(textController.text); } }, decoration: InputDecoration( hintText: mode.value == 0 ? "点击输入关键字搜索" : "点击主播昵称搜索", hintStyle: AppStyle.textStyleWhite, border: OutlineInputBorder( borderRadius: AppStyle.radius16, borderSide: BorderSide(width: 4.w), ), filled: true, isDense: true, fillColor: Get.theme.primaryColor, contentPadding: AppStyle.edgeInsetsA32, ), ), ), ], ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/hot_live/hot_live_controller.dart ================================================ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; class HotliveController extends BasePageController { var siteId = Constant.kBiliBili.obs; var site = Sites.allSites[Constant.kBiliBili]!; @override void onInit() { scrollController.addListener(scrollListener); refreshData(); super.onInit(); } void scrollListener() { if (scrollController.position.pixels >= (scrollController.position.maxScrollExtent - 100.w)) { loadData(); } } void setSite(String id) { siteId.value = id; site = Sites.allSites[id]!; refreshData(); } @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.getRecommendRooms(page: page); return result.items .map((e) => LiveRoomItemExt( roomId: e.roomId, title: e.title, cover: e.cover, userName: e.userName, online: e.online, )) .toList(); } @override void onClose() { scrollController.removeListener(scrollListener); super.onClose(); } } class LiveRoomItemExt extends LiveRoomItem { LiveRoomItemExt({ required super.roomId, required super.title, required super.cover, required super.userName, super.online = 0, }); AppFocusNode focusNode = AppFocusNode(); } ================================================ FILE: simple_live_tv_app/lib/modules/hot_live/hot_live_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/live_room_card.dart'; class HotLivePage extends GetView { const HotLivePage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", //autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "热门直播", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), Obx( () => Visibility( visible: controller.loadding.value, child: SizedBox( width: 48.w, height: 48.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 4.w, ), ), ), ), AppStyle.hGap24, // HighlightButton( // focusNode: AppFocusNode(), // iconData: Icons.refresh, // text: "刷新", // onTap: () { // controller.refreshData(); // }, // ), AppStyle.hGap48, ], ), AppStyle.vGap24, Wrap( alignment: WrapAlignment.center, spacing: 36.w, children: Sites.supportSites .map( (e) => Obx( () => HighlightButton( icon: Image.asset( e.logo, width: 48.w, height: 48.w, ), text: e.name, selected: controller.siteId.value == e.id, focusNode: AppFocusNode(), onTap: () { controller.setSite(e.id); }, ), ), ) .toList(), ), AppStyle.vGap24, Expanded( child: Obx( () => MasonryGridView.count( padding: AppStyle.edgeInsetsA48, itemCount: controller.list.length, crossAxisCount: 5, crossAxisSpacing: 48.w, mainAxisSpacing: 40.w, controller: controller.scrollController, itemBuilder: (_, i) { var item = controller.list[i]; if (i == 0) { Future.delayed(Duration.zero, () { if (controller.currentPage == 2) { item.focusNode.requestFocus(); } }); } return LiveRoomCard( cover: item.cover, anchor: item.userName, title: item.title, focusNode: item.focusNode, roomId: item.roomId, online: item.online, onTap: () { AppNavigator.toLiveRoomDetail( site: controller.site, roomId: item.roomId, ); }, ); }, ), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/live_room/live_room_controller.dart ================================================ import 'dart:async'; import 'package:canvas_danmaku/models/danmaku_content_item.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:media_kit/media_kit.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/event_bus.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/models/db/follow_user.dart'; import 'package:simple_live_tv_app/models/db/history.dart'; import 'package:simple_live_tv_app/modules/live_room/player/player_controller.dart'; import 'package:simple_live_tv_app/services/db_service.dart'; import 'package:simple_live_tv_app/services/follow_user_service.dart'; class LiveRoomController extends PlayerController with WidgetsBindingObserver { final Site pSite; final String pRoomId; late LiveDanmaku liveDanmaku; LiveRoomController({ required this.pSite, required this.pRoomId, }) { rxSite = pSite.obs; rxRoomId = pRoomId.obs; liveDanmaku = site.liveSite.getDanmaku(); } final FocusNode focusNode = FocusNode(); late Rx rxSite; Site get site => rxSite.value; late Rx rxRoomId; String get roomId => rxRoomId.value; Rx detail = Rx(null); var online = 0.obs; var followed = false.obs; var liveStatus = false.obs; /// 清晰度数据 RxList qualites = RxList(); /// 当前清晰度 var currentQuality = -1; var currentQualityInfo = "".obs; /// 线路数据 RxList playUrls = RxList(); Map? playHeaders; /// 当前线路 var currentLineIndex = -1; var currentLineInfo = "".obs; /// 是否处于后台 var isBackground = false; var datetime = "00:00".obs; void initTimer() { Timer.periodic(const Duration(seconds: 1), (timer) { var now = DateTime.now(); datetime.value = "${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}"; }); } /// 双击退出Flag bool doubleClickExit = false; /// 双击退出Timer Timer? doubleClickTimer; @override void onInit() { initTimer(); showDanmakuState.value = AppSettingsController.instance.danmuEnable.value; followed.value = DBService.instance.getFollowExist("${site.id}_$roomId"); loadData(); super.onInit(); } void refreshRoom() { //messages.clear(); liveDanmaku.stop(); loadData(); } /// 初始化弹幕接收事件 void initDanmau() { liveDanmaku.onMessage = onWSMessage; } /// 接收到WebSocket信息 void onWSMessage(LiveMessage msg) { if (msg.type == LiveMessageType.chat) { // 关键词屏蔽检查 for (var keyword in AppSettingsController.instance.shieldList) { Pattern? pattern; if (Utils.isRegexFormat(keyword)) { String removedSlash = Utils.removeRegexFormat(keyword); try { pattern = RegExp(removedSlash); } catch (e) { // should avoid this during add keyword Log.d("关键词:$keyword 正则格式错误"); } } else { pattern = keyword; } if (pattern != null && msg.message.contains(pattern)) { Log.d("关键词:$keyword\n已屏蔽消息内容:${msg.message}"); return; } } if (!liveStatus.value || isBackground) { return; } addDanmaku([ DanmakuContentItem( msg.message, color: Color.fromARGB(255, msg.color.r, msg.color.g, msg.color.b), ), ]); } else if (msg.type == LiveMessageType.online) { online.value = msg.data; } else if (msg.type == LiveMessageType.superChat) { //superChats.add(msg.data); } } /// 加载直播间信息 void loadData() async { try { SmartDialog.showLoading(msg: ""); pageLoadding.value = true; detail.value = await site.liveSite.getRoomDetail(roomId: roomId); addHistory(); online.value = detail.value!.online; liveStatus.value = detail.value!.status || detail.value!.isRecord; if (liveStatus.value) { getPlayQualites(); } if (detail.value!.isRecord) { SmartDialog.showToast("当前主播未开播,正在轮播录像"); } initDanmau(); liveDanmaku.start(detail.value?.danmakuData); } catch (e) { SmartDialog.showToast(e.toString()); } finally { SmartDialog.dismiss(status: SmartStatus.loading); pageLoadding.value = false; } } /// 初始化播放器 void getPlayQualites() async { qualites.clear(); currentQuality = -1; try { var playQualites = await site.liveSite.getPlayQualites(detail: detail.value!); if (playQualites.isEmpty) { SmartDialog.showToast("无法读取播放清晰度"); return; } qualites.value = playQualites; var qualityLevel = AppSettingsController.instance.qualityLevel.value; if (qualityLevel == 2) { //最高 currentQuality = 0; } else if (qualityLevel == 0) { //最低 currentQuality = playQualites.length - 1; } else { //中间值 int middle = (playQualites.length / 2).floor(); currentQuality = middle; } getPlayUrl(); } catch (e) { Log.logPrint(e); SmartDialog.showToast("无法读取播放清晰度"); } } void getPlayUrl() async { playUrls.clear(); currentQualityInfo.value = qualites[currentQuality].quality; currentLineInfo.value = ""; currentLineIndex = -1; var playUrl = await site.liveSite .getPlayUrls(detail: detail.value!, quality: qualites[currentQuality]); if (playUrl.urls.isEmpty) { SmartDialog.showToast("无法读取播放地址"); return; } playUrls.value = playUrl.urls; playHeaders = playUrl.headers; currentLineIndex = 0; currentLineInfo.value = "线路${currentLineIndex + 1}"; //重置错误次数 mediaErrorRetryCount = 0; setPlayer(); } void changePlayLine(int index) { currentLineIndex = index; //重置错误次数 mediaErrorRetryCount = 0; setPlayer(); } void setPlayer() async { currentLineInfo.value = "线路${currentLineIndex + 1}"; errorMsg.value = ""; // 初始化播放器并设置 ao 参数 await initializePlayer(); player.open( Media( playUrls[currentLineIndex], httpHeaders: playHeaders, ), ); Log.d("播放链接\r\n:${playUrls[currentLineIndex]}"); } @override void mediaEnd() async { if (mediaErrorRetryCount < 2) { Log.d("播放结束,尝试第${mediaErrorRetryCount + 1}次刷新"); if (mediaErrorRetryCount == 1) { //延迟一秒再刷新 await Future.delayed(const Duration(seconds: 1)); } mediaErrorRetryCount += 1; //刷新一次 setPlayer(); return; } Log.d("播放结束"); // 遍历线路,如果全部链接都断开就是直播结束了 if (playUrls.length - 1 == currentLineIndex) { liveStatus.value = false; } else { changePlayLine(currentLineIndex + 1); //setPlayer(); } } int mediaErrorRetryCount = 0; @override void mediaError(String error) async { if (mediaErrorRetryCount < 2) { Log.d("播放失败,尝试第${mediaErrorRetryCount + 1}次刷新"); if (mediaErrorRetryCount == 1) { //延迟一秒再刷新 await Future.delayed(const Duration(seconds: 1)); } mediaErrorRetryCount += 1; //刷新一次 setPlayer(); return; } if (playUrls.length - 1 == currentLineIndex) { errorMsg.value = "播放失败"; SmartDialog.showToast("播放失败:$error"); } else { //currentLineIndex += 1; //setPlayer(); changePlayLine(currentLineIndex + 1); } } /// 添加历史记录 void addHistory() { if (detail.value == null) { return; } var id = "${site.id}_$roomId"; var history = DBService.instance.getHistory(id); if (history != null) { history.updateTime = DateTime.now(); } history ??= History( id: id, roomId: roomId, siteId: site.id, userName: detail.value?.userName ?? "", face: detail.value?.userAvatar ?? "", updateTime: DateTime.now(), ); DBService.instance.addOrUpdateHistory(history); } /// 关注用户 void followUser() { if (detail.value == null) { return; } var id = "${site.id}_$roomId"; DBService.instance.addFollow( FollowUser( id: id, roomId: roomId, siteId: site.id, userName: detail.value?.userName ?? "", face: detail.value?.userAvatar ?? "", addTime: DateTime.now(), ), ); followed.value = true; EventBus.instance.emit(Constant.kUpdateFollow, id); SmartDialog.showToast("已关注"); } /// 取消关注用户 void removeFollowUser() async { if (detail.value == null) { return; } // if (!await Utils.showAlertDialog("确定要取消关注该用户吗?", title: "取消关注")) { // return; // } var id = "${site.id}_$roomId"; DBService.instance.deleteFollow(id); followed.value = false; EventBus.instance.emit(Constant.kUpdateFollow, id); SmartDialog.showToast("已取消关注"); } void resetRoom(Site site, String roomId) async { if (this.site == site && this.roomId == roomId) { return; } rxSite.value = site; rxRoomId.value = roomId; // 清除全部消息 liveDanmaku.stop(); danmakuController?.clear(); // 重新设置LiveDanmaku liveDanmaku = site.liveSite.getDanmaku(); // 停止播放 await player.stop(); // 刷新信息 loadData(); } void nextChannel() { //读取正在直播的频道 var liveChannels = FollowUserService.instance.livingList; if (liveChannels.isEmpty) { SmartDialog.showToast("没有正在直播的频道"); return; } var index = liveChannels .indexWhere((element) => element.id == "${site.id}_$roomId"); // if (index == -1) { // //当前频道不在列表中 // return; // } index += 1; if (index >= liveChannels.length) { index = 0; } var nextChannel = liveChannels[index]; resetRoom(Sites.allSites[nextChannel.siteId]!, nextChannel.roomId); } void prevChannel() { //读取正在直播的频道 var liveChannels = FollowUserService.instance.livingList; if (liveChannels.isEmpty) { SmartDialog.showToast("没有正在直播的频道"); return; } var index = liveChannels .indexWhere((element) => element.id == "${site.id}_$roomId"); // if (index == -1) { // //当前频道不在列表中 // return; // } index -= 1; if (index < 0) { index = liveChannels.length - 1; } var nextChannel = liveChannels[index]; resetRoom(Sites.allSites[nextChannel.siteId]!, nextChannel.roomId); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); if (state == AppLifecycleState.paused) { Log.d("进入后台"); //进入后台,关闭弹幕 danmakuController?.clear(); isBackground = true; } else //返回前台 if (state == AppLifecycleState.resumed) { Log.d("返回前台"); isBackground = false; } } @override void onClose() { liveDanmaku.stop(); danmakuController = null; super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/modules/live_room/live_room_page.dart ================================================ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/modules/live_room/live_room_controller.dart'; import 'package:simple_live_tv_app/modules/live_room/player/player_controls.dart'; class LiveRoomPage extends GetView { const LiveRoomPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return PopScope( canPop: false, onPopInvokedWithResult: (didPop, result) { if (!didPop) { //双击返回键退出 if (controller.doubleClickExit) { controller.doubleClickTimer?.cancel(); Get.back(); return; } controller.doubleClickExit = true; SmartDialog.showToast("再按一次退出播放器"); controller.doubleClickTimer = Timer(const Duration(seconds: 2), () { controller.doubleClickExit = false; controller.doubleClickTimer!.cancel(); }); } }, child: KeyboardListener( focusNode: controller.focusNode, autofocus: true, onKeyEvent: onKeyEvent, child: Scaffold( backgroundColor: Colors.black, body: Obx( () => buildMediaPlayer(), ), ), ), ); } void onKeyEvent(KeyEvent key) { if (key is KeyUpEvent) { return; } Log.logPrint(key); // if (key.logicalKey == LogicalKeyboardKey.escape || // key.logicalKey == LogicalKeyboardKey.backspace || // key.logicalKey == LogicalKeyboardKey.goBack) { // // Get.back(); // return; // } // 点击OK、Enter、Select键时显示/隐藏控制器 if (key.logicalKey == LogicalKeyboardKey.select || key.logicalKey == LogicalKeyboardKey.enter || key.logicalKey == LogicalKeyboardKey.space) { if (!controller.showControlsState.value) { controller.showControls(); } else { controller.hideControls(); } return; } // 点击Menu打开/关闭设置 if (key.logicalKey == LogicalKeyboardKey.keyM || key.logicalKey == LogicalKeyboardKey.contextMenu || key.logicalKey == LogicalKeyboardKey.arrowRight) { showPlayerSettings(controller); return; } // 点击左键显示关注用户 if (key.logicalKey == LogicalKeyboardKey.arrowLeft) { showFollowUser(controller); return; } // // 点击右键关注/取消关注 // if (key.logicalKey == LogicalKeyboardKey.arrowRight) { // if (controller.followed.value) { // controller.removeFollowUser(); // } else { // controller.followUser(); // } // return; // } // 点击上键切换上一个直播 if (key.logicalKey == LogicalKeyboardKey.arrowUp) { controller.prevChannel(); return; } // 点击下键切换下一个直播 if (key.logicalKey == LogicalKeyboardKey.arrowDown) { controller.nextChannel(); return; } } Widget buildMediaPlayer() { var boxFit = BoxFit.contain; double? aspectRatio; if (AppSettingsController.instance.scaleMode.value == 0) { boxFit = BoxFit.contain; } else if (AppSettingsController.instance.scaleMode.value == 1) { boxFit = BoxFit.fill; } else if (AppSettingsController.instance.scaleMode.value == 2) { boxFit = BoxFit.cover; } else if (AppSettingsController.instance.scaleMode.value == 3) { boxFit = BoxFit.contain; aspectRatio = 16 / 9; } else if (AppSettingsController.instance.scaleMode.value == 4) { boxFit = BoxFit.contain; aspectRatio = 4 / 3; } return Stack( children: [ Video( key: controller.globalPlayerKey, controller: controller.videoController, pauseUponEnteringBackgroundMode: AppSettingsController.instance.playerAutoPause.value, resumeUponEnteringForegroundMode: AppSettingsController.instance.playerAutoPause.value, controls: (state) { return playerControls(state, controller); }, aspectRatio: aspectRatio, fit: boxFit, ), Obx( () => Visibility( visible: !controller.liveStatus.value && !controller.pageLoadding.value, child: Center( child: Text( "未开播", style: AppStyle.textStyleWhite, ), ), ), ), ], ); } } ================================================ FILE: simple_live_tv_app/lib/modules/live_room/player/player_controller.dart ================================================ import 'dart:async'; import 'dart:io'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:get/get.dart'; import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; mixin PlayerMixin { GlobalKey globalPlayerKey = GlobalKey(); GlobalKey globalDanmuKey = GlobalKey(); /// 播放器实例 late final player = Player( configuration: const PlayerConfiguration( title: "Simple Live Player", // bufferSize: // // media-kit #549 // AppSettingsController.instance.playerBufferSize.value * 1024 * 1024, ), ); /// 初始化播放器并设置 ao 参数 Future initializePlayer() async { var pp = player.platform as NativePlayer; // media_kit 仓库更新导致的问题,临时解决办法 if (Platform.isAndroid) { await pp.setProperty('force-seekable', 'yes'); } } /// 视频控制器 late final videoController = VideoController( player, configuration: AppSettingsController.instance.playerCompatMode.value ? const VideoControllerConfiguration( vo: 'mediacodec_embed', hwdec: 'mediacodec', ) : VideoControllerConfiguration( enableHardwareAcceleration: AppSettingsController.instance.hardwareDecode.value, androidAttachSurfaceAfterVideoParameters: false, ), ); } mixin PlayerStateMixin on PlayerMixin { /// 是否显示弹幕 RxBool showDanmakuState = false.obs; /// 是否显示控制器 RxBool showControlsState = false.obs; /// 是否显示设置窗口 RxBool showSettingState = false.obs; /// 是否显示弹幕设置窗口 RxBool showDanmakuSettingState = false.obs; /// 是否处于锁定控制器状态 RxBool lockControlsState = false.obs; /// 是否处于全屏状态 RxBool fullScreenState = false.obs; /// 显示手势Tip RxBool showGestureTip = false.obs; /// 手势Tip文本 RxString gestureTipText = "".obs; /// 显示提示底部Tip RxBool showBottomTip = false.obs; /// 提示底部Tip文本 RxString bottomTipText = "".obs; /// 自动隐藏控制器计时器 Timer? hideControlsTimer; /// 自动隐藏提示计时器 Timer? hideSeekTipTimer; Widget? danmakuView; var showQualites = false.obs; var showLines = false.obs; /// 隐藏控制器 void hideControls() { showControlsState.value = false; hideControlsTimer?.cancel(); } void setLockState() { lockControlsState.value = !lockControlsState.value; if (lockControlsState.value) { showControlsState.value = false; } else { showControlsState.value = true; } } /// 显示控制器 void showControls() { showControlsState.value = true; resetHideControlsTimer(); } /// 开始隐藏控制器计时 /// - 当点击控制器上时功能时需要重新计时 void resetHideControlsTimer() { hideControlsTimer?.cancel(); hideControlsTimer = Timer( const Duration( seconds: 5, ), hideControls, ); } void updateScaleMode() { var boxFit = BoxFit.contain; double? aspectRatio; if (player.state.width != null && player.state.height != null) { aspectRatio = player.state.width! / player.state.height!; } if (AppSettingsController.instance.scaleMode.value == 0) { boxFit = BoxFit.contain; } else if (AppSettingsController.instance.scaleMode.value == 1) { boxFit = BoxFit.fill; } else if (AppSettingsController.instance.scaleMode.value == 2) { boxFit = BoxFit.cover; } else if (AppSettingsController.instance.scaleMode.value == 3) { boxFit = BoxFit.contain; aspectRatio = 16 / 9; } else if (AppSettingsController.instance.scaleMode.value == 4) { boxFit = BoxFit.contain; aspectRatio = 4 / 3; } globalPlayerKey.currentState?.update( aspectRatio: aspectRatio, fit: boxFit, ); } } mixin PlayerDanmakuMixin on PlayerStateMixin { /// 弹幕控制器 DanmakuController? danmakuController; void initDanmakuController(DanmakuController e) { danmakuController = e; // danmakuController?.updateOption( // DanmakuOption( // fontSize: AppSettingsController.instance.danmuSize.value.w, // area: AppSettingsController.instance.danmuArea.value, // duration: AppSettingsController.instance.danmuSpeed.value, // opacity: AppSettingsController.instance.danmuOpacity.value, // strokeWidth: AppSettingsController.instance.danmuStrokeWidth.value.w, // ), // ); } void updateDanmuOption(DanmakuOption? option) { if (danmakuController == null || option == null) return; danmakuController!.updateOption(option); } void disposeDanmakuController() { danmakuController?.clear(); } void addDanmaku(List items) { if (!showDanmakuState.value) { return; } for (var item in items) { danmakuController?.addDanmaku(item); } } } mixin PlayerSystemMixin on PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin { final DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); /// 初始化一些系统状态 void initSystem() async { // 屏幕常亮 WakelockPlus.enable(); // 开始隐藏计时 resetHideControlsTimer(); } /// 释放一些系统状态 Future resetSystem() async { await WakelockPlus.disable(); } /// 是否是IOS16以下 Future beforeIOS16() async { if (Platform.isIOS) { var info = await deviceInfo.iosInfo; var version = info.systemVersion; var versionInt = int.tryParse(version.split('.').first) ?? 0; return versionInt < 16; } else { return false; } } } class PlayerController extends BaseController with PlayerMixin, PlayerStateMixin, PlayerDanmakuMixin, PlayerSystemMixin { @override void onInit() { initSystem(); initStream(); super.onInit(); } var width = 0.obs; var height = 0.obs; StreamSubscription? _errorSubscription; StreamSubscription? _completedSubscription; StreamSubscription? _widthSubscription; StreamSubscription? _heightSubscription; StreamSubscription? _logSubscription; void initStream() { _errorSubscription = player.stream.error.listen((event) { Log.d("播放器错误:$event"); if (event.contains('no sound.')) { return; } //SmartDialog.showToast(event); mediaError(event); }); _completedSubscription = player.stream.completed.listen((event) { if (event) { mediaEnd(); } }); _logSubscription = player.stream.log.listen((event) { Log.d("播放器日志:$event"); }); _widthSubscription = player.stream.width.listen((event) { Log.w( 'width:$event W:${(player.state.width)} H:${(player.state.height)}'); width.value = event ?? 0; // isVertical.value = // (player.state.height ?? 9) > (player.state.width ?? 16); }); _heightSubscription = player.stream.height.listen((event) { Log.w( 'height:$event W:${(player.state.width)} H:${(player.state.height)}'); height.value = event ?? 0; // isVertical.value = // (player.state.height ?? 9) > (player.state.width ?? 16); }); } void disposeStream() { _errorSubscription?.cancel(); _completedSubscription?.cancel(); _widthSubscription?.cancel(); _heightSubscription?.cancel(); _logSubscription?.cancel(); } void mediaEnd() {} void mediaError(String error) {} @override void onClose() async { Log.w("播放器关闭"); disposeStream(); disposeDanmakuController(); await resetSystem(); await player.dispose(); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/modules/live_room/player/player_controls.dart ================================================ import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/modules/live_room/live_room_controller.dart'; import 'package:simple_live_tv_app/services/follow_user_service.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/anchor_card.dart'; import 'package:simple_live_tv_app/widgets/settings_item_widget.dart'; import 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart'; Widget playerControls(VideoState videoState, LiveRoomController controller) { return buildControls(videoState, controller); } Widget buildControls(VideoState videoState, LiveRoomController controller) { return Stack( children: [ Container(), buildDanmuView(videoState, controller), // 点击播放器打开设置 Positioned.fill( child: GestureDetector(onTap: () => showPlayerSettings(controller)), ), Center( child: // 中间 StreamBuilder( stream: videoState.widget.controller.player.stream.buffering, initialData: videoState.widget.controller.player.state.buffering, builder: (_, s) => Visibility( visible: s.data ?? false, child: SizedBox( width: 64.w, height: 64.w, child: CircularProgressIndicator( strokeWidth: 8.w, color: Colors.white, ), ), ), ), ), // 顶部 Obx( () => AnimatedPositioned( left: 0, right: 0, top: (controller.showControlsState.value && !controller.lockControlsState.value) ? 0 : -200.w, duration: const Duration(milliseconds: 200), child: Container( padding: EdgeInsets.only( left: 32.w, right: 32.w, top: 24.w, bottom: 24.w, ), decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [Colors.transparent, Colors.black87], ), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( controller.detail.value?.title ?? '正在读取直播信息...', maxLines: 1, overflow: TextOverflow.ellipsis, style: AppStyle.textStyleWhite, ), Text( "${controller.detail.value?.userName} · ${controller.followed.value ? "已关注" : "未关注"}", maxLines: 1, overflow: TextOverflow.ellipsis, style: AppStyle.textStyleWhite.copyWith(fontSize: 24.w), ), ], ), ), Obx( () => Text( controller.datetime.value, style: AppStyle.titleStyleWhite, ), ), ], ), ), ), ), // 底部 Obx( () => AnimatedPositioned( left: 0, right: 0, bottom: (controller.showControlsState.value && !controller.lockControlsState.value) ? 0 : -300.w, duration: const Duration(milliseconds: 200), child: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.transparent, Colors.black87], ), ), padding: EdgeInsets.only( left: 32.w, right: 32.w, bottom: 24.w, top: 24.w, ), child: Column( children: [ Row( children: [ //清晰度 Obx( () => Text( "清晰度: ${controller.currentQualityInfo.value}", style: AppStyle.textStyleWhite, ), ), //线路 AppStyle.hGap32, Obx( () => Text( "线路:${controller.currentLineInfo.value}", style: AppStyle.textStyleWhite, ), ), //弹幕开关 AppStyle.hGap32, Obx( () => Text( "弹幕: ${controller.showDanmakuState.value ? "开" : "关"}", style: AppStyle.textStyleWhite, ), ), //分辨率 AppStyle.hGap32, Obx( () => Text( "分辨率: ${controller.width.value}x${controller.height.value}", style: AppStyle.textStyleWhite, ), ), ], ), AppStyle.vGap12, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Icon( Icons.arrow_circle_up_rounded, color: Colors.white, size: 40.w, ), AppStyle.hGap16, Text("上一频道", style: AppStyle.textStyleWhite), AppStyle.hGap32, Icon( Icons.arrow_circle_down_rounded, color: Colors.white, size: 40.w, ), AppStyle.hGap16, Text("下一频道", style: AppStyle.textStyleWhite), AppStyle.hGap32, Icon( Icons.arrow_circle_left_outlined, color: Colors.white, size: 40.w, ), AppStyle.hGap16, Text("关注列表", style: AppStyle.textStyleWhite), AppStyle.hGap32, Icon( Icons.arrow_circle_right_outlined, color: Colors.white, size: 40.w, ), AppStyle.hGap16, Icon(Icons.menu, color: Colors.white, size: 44.w), AppStyle.hGap16, Text("设置", style: AppStyle.textStyleWhite), ], ), ], ), ), ), ), ], ); } Widget buildDanmuView(VideoState videoState, LiveRoomController controller) { var padding = MediaQuery.of(videoState.context).padding; controller.danmakuView ??= DanmakuScreen( key: controller.globalDanmuKey, createdController: controller.initDanmakuController, option: DanmakuOption( fontSize: AppSettingsController.instance.danmuSize.value.w, area: AppSettingsController.instance.danmuArea.value, duration: AppSettingsController.instance.danmuSpeed.value.toInt(), opacity: AppSettingsController.instance.danmuOpacity.value, ), ); return Positioned.fill( top: padding.top, bottom: padding.bottom, child: Obx( () => Offstage( offstage: !controller.showDanmakuState.value, child: Padding( padding: controller.fullScreenState.value ? EdgeInsets.only( top: AppSettingsController.instance.danmuTopMargin.value, bottom: AppSettingsController.instance.danmuBottomMargin.value, ) : EdgeInsets.zero, child: controller.danmakuView!, ), ), ), ); } // void showLinesInfo(LiveRoomController controller) { // Utils.showRightDialog( // title: "线路", // useSystem: true, // child: ListView.builder( // padding: EdgeInsets.zero, // itemCount: controller.playUrls.length, // itemBuilder: (_, i) { // return ListTile( // selected: controller.currentLineIndex == i, // title: Text.rich( // TextSpan( // text: "线路${i + 1}", // children: [ // WidgetSpan( // child: Container( // decoration: BoxDecoration( // borderRadius: AppStyle.radius4, // border: Border.all( // color: Colors.grey, // ), // ), // padding: AppStyle.edgeInsetsH4, // margin: AppStyle.edgeInsetsL8, // child: Text( // controller.playUrls[i].contains(".flv") ? "FLV" : "HLS", // style: const TextStyle( // fontSize: 12, // ), // ), // )), // ], // ), // style: const TextStyle(fontSize: 14), // ), // minLeadingWidth: 16, // onTap: () { // Utils.hideRightDialog(); // //controller.currentLineIndex = i; // //controller.setPlayer(); // controller.changePlayLine(i); // }, // ); // }, // ), // ); // } // void showQualitesInfo(LiveRoomController controller) { // Utils.showRightDialog( // title: "清晰度", // useSystem: true, // child: ListView.builder( // padding: EdgeInsets.zero, // itemCount: controller.qualites.length, // itemBuilder: (_, i) { // var item = controller.qualites[i]; // return ListTile( // selected: controller.currentQuality == i, // title: Text( // item.quality, // style: const TextStyle(fontSize: 14), // ), // minLeadingWidth: 16, // onTap: () { // Utils.hideRightDialog(); // controller.currentQuality = i; // controller.getPlayUrl(); // }, // ); // }, // ), // ); // } void showPlayerSettings(LiveRoomController controller) { // 移除焦点 controller.focusNode.unfocus(); var followFocusNode = AppFocusNode()..isFoucsed.value = true; var qualityFoucsNode = AppFocusNode(); var lineFoucsNode = AppFocusNode(); var scaleFoucsNode = AppFocusNode(); var danmakuFoucsNode = AppFocusNode(); var danmakuSizeFoucsNode = AppFocusNode(); var danmakuSpeedFoucsNode = AppFocusNode(); var danmakuAreaFoucsNode = AppFocusNode(); var danmakuOpacityFoucsNode = AppFocusNode(); Utils.showSystemRightDialog( width: 800.w, child: Column( children: [ AppStyle.vGap24, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", onTap: () { //Utils.hideRightDialog(); Get.back(); }, ), AppStyle.hGap32, Text( "设置", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), ], ), Expanded( child: ListView( padding: AppStyle.edgeInsetsA48, children: [ Obx( () => SettingsItemWidget( foucsNode: followFocusNode, autofocus: followFocusNode.isFoucsed.value, title: "关注用户", items: const {false: "否", true: "是"}, value: controller.followed.value, onChanged: (e) { if (e) { controller.followUser(); } else { controller.removeFollowUser(); } }, ), ), Divider(color: Colors.grey.withAlpha(50), height: 36.w), AppStyle.vGap24, Padding( padding: AppStyle.edgeInsetsH20, child: Text( "清晰度与线路", style: AppStyle.textStyleWhite.copyWith( fontWeight: FontWeight.bold, ), ), ), AppStyle.vGap24, // 清晰度切换 Obx( () => SettingsItemWidget( title: "清晰度", foucsNode: qualityFoucsNode, autofocus: qualityFoucsNode.isFoucsed.value, items: controller.qualites .asMap() .map((i, e) => MapEntry(i, e.quality)) .cast(), value: controller.currentQuality, onChanged: (e) { Get.back(); controller.currentQuality = e; controller.getPlayUrl(); }, ), ), AppStyle.vGap32, // 线路切换 Obx( () => SettingsItemWidget( title: "线路", foucsNode: lineFoucsNode, autofocus: lineFoucsNode.isFoucsed.value, items: controller.playUrls .asMap() .map((i, e) => MapEntry(i, "线路${i + 1}")) .cast(), value: controller.currentLineIndex, onChanged: (e) { Get.back(); controller.changePlayLine(e); }, ), ), Divider(color: Colors.grey.withAlpha(50), height: 36.w), Padding( padding: AppStyle.edgeInsetsH20, child: Text( "播放器", style: AppStyle.textStyleWhite.copyWith( fontWeight: FontWeight.bold, ), ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: scaleFoucsNode, autofocus: scaleFoucsNode.isFoucsed.value, title: "画面比例", items: const {0: "适应", 1: "拉伸", 2: "铺满", 3: "16:9", 4: "4:3"}, value: AppSettingsController.instance.scaleMode.value, onChanged: (e) { AppSettingsController.instance.setScaleMode(e); controller.updateScaleMode(); }, ), ), Divider(color: Colors.grey.withAlpha(50), height: 36.w), Padding( padding: AppStyle.edgeInsetsH20, child: Text( "弹幕", style: AppStyle.textStyleWhite.copyWith( fontWeight: FontWeight.bold, ), ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: danmakuFoucsNode, autofocus: danmakuFoucsNode.isFoucsed.value, title: "弹幕开关", items: const {0: "关", 1: "开"}, value: controller.showDanmakuState.value ? 1 : 0, onChanged: (e) { controller.showDanmakuState.value = e == 1; AppSettingsController.instance.setDanmuEnable(e == 1); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: danmakuSizeFoucsNode, autofocus: danmakuSizeFoucsNode.isFoucsed.value, title: "弹幕大小", items: { 24.0: "24", 32.0: "32", 40.0: "40", 48.0: "48", 56.0: "56", 64.0: "64", 72.0: "72", }, value: AppSettingsController.instance.danmuSize.value, onChanged: (e) { AppSettingsController.instance.setDanmuSize(e); controller.updateDanmuOption( controller.danmakuController?.option.copyWith( fontSize: (e as double).w, ), ); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: danmakuSpeedFoucsNode, autofocus: danmakuSpeedFoucsNode.isFoucsed.value, title: "弹幕速度", items: { 18.0: "很慢", 14.0: "较慢", 12.0: "慢", 10.0: "正常", 8.0: "快", 6.0: "较快", 4.0: "很快", }, value: AppSettingsController.instance.danmuSpeed.value, onChanged: (e) { AppSettingsController.instance.setDanmuSpeed(e); controller.updateDanmuOption( controller.danmakuController?.option.copyWith( duration: (e as double).toInt(), ), ); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: danmakuAreaFoucsNode, autofocus: danmakuAreaFoucsNode.isFoucsed.value, title: "显示区域", items: {0.25: "1/4", 0.5: "1/2", 0.75: "3/4", 1.0: "全屏"}, value: AppSettingsController.instance.danmuArea.value, onChanged: (e) { AppSettingsController.instance.setDanmuArea(e); controller.updateDanmuOption( controller.danmakuController?.option.copyWith( area: e as double, ), ); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: danmakuOpacityFoucsNode, autofocus: danmakuOpacityFoucsNode.isFoucsed.value, title: "不透明度", items: { 0.1: "10%", 0.2: "20%", 0.3: "30%", 0.4: "40%", 0.5: "50%", 0.6: "60%", 0.7: "70%", 0.8: "80%", 0.9: "90%", 1.0: "100%", }, value: AppSettingsController.instance.danmuOpacity.value, onChanged: (e) { AppSettingsController.instance.setDanmuOpacity(e); controller.updateDanmuOption( controller.danmakuController?.option.copyWith( opacity: e as double, ), ); }, ), ), ], ), ), ], ), ).then((value) { // 还原焦点 controller.focusNode.requestFocus(); }); } void showFollowUser(LiveRoomController controller) { var currentIndex = 0; if (controller.followed.value) { currentIndex = FollowUserService.instance.livingList.indexWhere( (e) => e.id == "${controller.rxSite.value.id}_${controller.detail.value?.roomId}", ); if (currentIndex == -1) { currentIndex = 0; } } Utils.showSystemRightDialog( width: 800.w, child: Column( children: [ AppStyle.vGap24, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: currentIndex == 0 && FollowUserService.instance.livingList.isEmpty, onTap: () { // Utils.hideRightDialog(); Get.back(); }, ), AppStyle.hGap32, Text( "我的关注", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), ], ), Expanded( child: Stack( children: [ Obx( () => ListView.separated( itemCount: FollowUserService.instance.livingList.length, separatorBuilder: (context, index) => AppStyle.vGap32, padding: AppStyle.edgeInsetsA40.copyWith( left: 48.w, right: 48.w, ), itemBuilder: (_, i) { var item = FollowUserService.instance.livingList[i]; var site = Sites.allSites[item.siteId]!; return AnchorCard( face: item.face, name: item.userName, siteId: item.siteId, liveStatus: item.liveStatus.value, roomId: item.roomId, autofocus: i == currentIndex, onTap: () { controller.resetRoom(site, item.roomId); Get.back(); }, ); }, ), ), Obx( () => Visibility( visible: FollowUserService.instance.list.isEmpty, child: const AppEmptyWidget(text: "关注列表为空,快去关注一些主播吧"), ), ), ], ), ), ], ), ).then((value) { // 还原焦点 controller.focusNode.requestFocus(); }); } ================================================ FILE: simple_live_tv_app/lib/modules/search/anchor/search_anchor_controller.dart ================================================ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; class SearchAnchorController extends BasePageController { final String keyword; SearchAnchorController(this.keyword); var siteId = Constant.kBiliBili.obs; var site = Sites.allSites[Constant.kBiliBili]!; @override void onInit() { scrollController.addListener(scrollListener); refreshData(); super.onInit(); } void scrollListener() { if (scrollController.position.pixels >= (scrollController.position.maxScrollExtent - 100.w)) { loadData(); } } void setSite(String id) { siteId.value = id; site = Sites.allSites[id]!; refreshData(); } @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.searchAnchors(keyword, page: page); return result.items .map((e) => LiveAnchorItemExt( roomId: e.roomId, avatar: e.avatar, liveStatus: e.liveStatus, userName: e.userName, )) .toList(); } @override void onClose() { scrollController.removeListener(scrollListener); super.onClose(); } } class LiveAnchorItemExt extends LiveAnchorItem { LiveAnchorItemExt({ required super.roomId, required super.avatar, required super.liveStatus, required super.userName, }); AppFocusNode focusNode = AppFocusNode(); } ================================================ FILE: simple_live_tv_app/lib/modules/search/anchor/search_anchor_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/search/anchor/search_anchor_controller.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/anchor_card.dart'; import 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart'; import 'package:simple_live_tv_app/widgets/status/app_error_widget.dart'; class SearchAnchorPage extends GetView { const SearchAnchorPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", //autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "搜索:${controller.keyword}", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), Obx( () => Visibility( visible: controller.loadding.value, child: SizedBox( width: 48.w, height: 48.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 4.w, ), ), ), ), AppStyle.hGap24, // HighlightButton( // focusNode: AppFocusNode(), // iconData: Icons.refresh, // text: "刷新", // onTap: () { // controller.refreshData(); // }, // ), AppStyle.hGap48, ], ), AppStyle.vGap24, Wrap( alignment: WrapAlignment.center, spacing: 36.w, children: Sites.supportSites .map( (e) => Obx( () => HighlightButton( icon: Image.asset( e.logo, width: 48.w, height: 48.w, ), text: e.name, selected: controller.siteId.value == e.id, focusNode: AppFocusNode(), onTap: () { controller.setSite(e.id); }, ), ), ) .toList(), ), AppStyle.vGap24, Expanded( child: Obx( () => Stack( children: [ MasonryGridView.count( padding: AppStyle.edgeInsetsA48, itemCount: controller.list.length, crossAxisCount: 3, crossAxisSpacing: 48.w, mainAxisSpacing: 40.w, controller: controller.scrollController, itemBuilder: (_, i) { var item = controller.list[i]; if (i == 0) { Future.delayed(Duration.zero, () { if (controller.currentPage == 2) { item.focusNode.requestFocus(); } }); } return AnchorCard( siteId: controller.siteId.value, name: item.userName, liveStatus: item.liveStatus ? 2 : 0, face: item.avatar, roomId: item.roomId, focusNode: item.focusNode, onTap: () { AppNavigator.toLiveRoomDetail( site: controller.site, roomId: item.roomId, ); }, ); }, ), Obx( () => Visibility( visible: controller.list.isEmpty && !controller.loadding.value && !controller.pageError.value, child: AppEmptyWidget( onRefresh: () { controller.refreshData(); }, ), ), ), Obx( () => Visibility( visible: controller.pageError.value && !controller.loadding.value, child: AppErrorWidget( errorMsg: controller.errorMsg.value, ), ), ), ], ), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/search/room/search_room_controller.dart ================================================ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get_rx/src/rx_types/rx_types.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart'; class SearchRoomController extends BasePageController { final String keyword; SearchRoomController(this.keyword); var siteId = Constant.kBiliBili.obs; var site = Sites.allSites[Constant.kBiliBili]!; @override void onInit() { scrollController.addListener(scrollListener); refreshData(); super.onInit(); } void scrollListener() { if (scrollController.position.pixels >= (scrollController.position.maxScrollExtent - 100.w)) { loadData(); } } void setSite(String id) { siteId.value = id; site = Sites.allSites[id]!; refreshData(); } @override Future> getData(int page, int pageSize) async { var result = await site.liveSite.searchRooms(keyword, page: page); return result.items .map((e) => LiveRoomItemExt( roomId: e.roomId, title: e.title, cover: e.cover, userName: e.userName, online: e.online, )) .toList(); } @override void onClose() { scrollController.removeListener(scrollListener); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/modules/search/room/search_room_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/search/room/search_room_controller.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/card/live_room_card.dart'; import 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart'; import 'package:simple_live_tv_app/widgets/status/app_error_widget.dart'; class SearchRoomPage extends GetView { const SearchRoomPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", //autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "搜索:${controller.keyword}", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), Obx( () => Visibility( visible: controller.loadding.value, child: SizedBox( width: 48.w, height: 48.w, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 4.w, ), ), ), ), AppStyle.hGap24, // HighlightButton( // focusNode: AppFocusNode(), // iconData: Icons.refresh, // text: "刷新", // onTap: () { // controller.refreshData(); // }, // ), AppStyle.hGap48, ], ), AppStyle.vGap24, Wrap( alignment: WrapAlignment.center, spacing: 36.w, children: Sites.supportSites .map( (e) => Obx( () => HighlightButton( icon: Image.asset( e.logo, width: 48.w, height: 48.w, ), text: e.name, selected: controller.siteId.value == e.id, focusNode: AppFocusNode(), onTap: () { controller.setSite(e.id); }, ), ), ) .toList(), ), AppStyle.vGap24, Expanded( child: Obx( () => Stack( children: [ MasonryGridView.count( padding: AppStyle.edgeInsetsA48, itemCount: controller.list.length, crossAxisCount: 5, crossAxisSpacing: 48.w, mainAxisSpacing: 40.w, controller: controller.scrollController, itemBuilder: (_, i) { var item = controller.list[i]; if (i == 0) { Future.delayed(Duration.zero, () { if (controller.currentPage == 2) { item.focusNode.requestFocus(); } }); } return LiveRoomCard( cover: item.cover, anchor: item.userName, title: item.title, focusNode: item.focusNode, roomId: item.roomId, online: item.online, onTap: () { AppNavigator.toLiveRoomDetail( site: controller.site, roomId: item.roomId, ); }, ); }, ), Obx( () => Visibility( visible: controller.list.isEmpty && !controller.loadding.value && !controller.pageError.value, child: AppEmptyWidget( onRefresh: () { controller.refreshData(); }, ), ), ), Obx( () => Visibility( visible: controller.pageError.value && !controller.loadding.value, child: AppErrorWidget( errorMsg: controller.errorMsg.value, ), ), ), ], ), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/modules/settings/settings_controller.dart ================================================ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; class SettingsController extends BaseController with GetTickerProviderStateMixin { late TabController tabController; var tabIndex = 0.obs; SettingsController() { tabController = TabController(length: 5, vsync: this); tabController.animation?.addListener(() { var currentIndex = (tabController.animation?.value ?? 0).round(); if (tabIndex.value == currentIndex) { return; } tabIndex.value = currentIndex; if (tabIndex.value == 0) { hardwareDecodeFocusNode.requestFocus(); } if (tabIndex.value == 1) { danmakuFoucsNode.requestFocus(); } if (tabIndex.value == 2) { autoUpdateFollowEnableFocusNode.requestFocus(); } if (tabIndex.value == 3) { bilibiliFoucsNode.requestFocus(); } if (tabIndex.value == 4) { versionFocusNode.requestFocus(); } }); } var hardwareDecodeFocusNode = AppFocusNode()..isFoucsed.value = true; var compatibleModeFocusNode = AppFocusNode(); var scaleFoucsNode = AppFocusNode(); var defaultQualityFocusNode = AppFocusNode(); var danmakuFoucsNode = AppFocusNode(); var danmakuSizeFoucsNode = AppFocusNode(); var danmakuSpeedFoucsNode = AppFocusNode(); var danmakuAreaFoucsNode = AppFocusNode(); var danmakuOpacityFoucsNode = AppFocusNode(); var danmakuStorkeFoucsNode = AppFocusNode(); var autoUpdateFollowEnableFocusNode = AppFocusNode(); var autoUpdateFollowDurationFocusNode = AppFocusNode(); var updateFollowThreadFocusNode = AppFocusNode(); var bilibiliFoucsNode = AppFocusNode(); var versionFocusNode = AppFocusNode(); void bilibiliTap() async { if (BiliBiliAccountService.instance.logined.value) { var result = await Utils.showAlertDialog("确定要退出哔哩哔哩账号吗?", title: "退出登录"); if (result) { BiliBiliAccountService.instance.logout(); } } else { AppNavigator.toBiliBiliLogin(); } } } ================================================ FILE: simple_live_tv_app/lib/modules/settings/settings_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/modules/settings/settings_controller.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; import 'package:simple_live_tv_app/services/follow_user_service.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_list_tile.dart'; import 'package:simple_live_tv_app/widgets/settings_item_widget.dart'; class SettingsPage extends GetView { const SettingsPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap32, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "设置", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), AppStyle.hGap24, const Spacer(), ], ), AppStyle.vGap48, Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Obx( () => HighlightButton( focusNode: AppFocusNode(), iconData: Icons.play_circle_outline, text: "播放", selected: controller.tabIndex.value == 0, onTap: () { controller.tabController.animateTo(0); }, ), ), AppStyle.hGap32, Obx( () => HighlightButton( focusNode: AppFocusNode(), iconData: Icons.subtitles_outlined, text: "弹幕", selected: controller.tabIndex.value == 1, onTap: () { controller.tabController.animateTo(1); }, ), ), AppStyle.hGap32, Obx( () => HighlightButton( focusNode: AppFocusNode(), iconData: Icons.favorite_border, text: "关注", selected: controller.tabIndex.value == 2, onTap: () { controller.tabController.animateTo(2); }, ), ), AppStyle.hGap32, Obx( () => HighlightButton( focusNode: AppFocusNode(), iconData: Icons.account_circle_outlined, selected: controller.tabIndex.value == 3, text: "账号", onTap: () { controller.tabController.animateTo(3); }, ), ), AppStyle.hGap32, Obx( () => HighlightButton( focusNode: AppFocusNode(), iconData: Icons.info_outline, selected: controller.tabIndex.value == 4, text: "关于", onTap: () { controller.tabController.animateTo(4); }, ), ), ], ), Expanded( child: SizedBox( width: 800.w, child: TabBarView( controller: controller.tabController, children: [ buildPlayerSettings(), buildDanmakuSettings(), buildFollowSettings(), buildAccountSettings(), buildAbout(), ], ), )), ], ), ); } Widget buildPlayerSettings() { return ListView( padding: AppStyle.edgeInsetsA48, children: [ Obx( () => SettingsItemWidget( foucsNode: controller.hardwareDecodeFocusNode, autofocus: controller.hardwareDecodeFocusNode.isFoucsed.value, title: "硬件解码", items: const { 0: "关", 1: "开", }, value: AppSettingsController.instance.hardwareDecode.value ? 1 : 0, onChanged: (e) { AppSettingsController.instance .setHardwareDecode(e == 1 ? true : false); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.compatibleModeFocusNode, autofocus: controller.compatibleModeFocusNode.isFoucsed.value, title: "兼容模式", items: const { 0: "关", 1: "开", }, value: AppSettingsController.instance.playerCompatMode.value ? 1 : 0, onChanged: (e) { AppSettingsController.instance .setPlayerCompatMode(e == 1 ? true : false); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.scaleFoucsNode, autofocus: controller.scaleFoucsNode.isFoucsed.value, title: "画面比例", items: const { 0: "适应", 1: "拉伸", 2: "铺满", 3: "16:9", 4: "4:3", }, value: AppSettingsController.instance.scaleMode.value, onChanged: (e) { AppSettingsController.instance.setScaleMode(e); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.defaultQualityFocusNode, autofocus: controller.defaultQualityFocusNode.isFoucsed.value, title: "默认清晰度", items: const { 0: "最低画质", 1: "中等画质", 2: "最高画质", }, value: AppSettingsController.instance.qualityLevel.value, onChanged: (e) { AppSettingsController.instance.setQualityLevel(e); }, ), ), ], ); } Widget buildFollowSettings() { return ListView( padding: AppStyle.edgeInsetsA48, children: [ Obx( () => SettingsItemWidget( foucsNode: controller.autoUpdateFollowEnableFocusNode, autofocus: controller.autoUpdateFollowEnableFocusNode.isFoucsed.value, title: "自动更新关注", items: const { 0: "关", 1: "开", }, value: AppSettingsController.instance.autoUpdateFollowEnable.value ? 1 : 0, onChanged: (e) { AppSettingsController.instance .setAutoUpdateFollowEnable(e == 1 ? true : false); FollowUserService.instance.initTimer(); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.autoUpdateFollowDurationFocusNode, autofocus: controller.autoUpdateFollowDurationFocusNode.isFoucsed.value, title: "自动更新间隔", items: const { 5: "5分钟", 10: "10分钟", 15: "15分钟", 20: "20分钟", 25: "25分钟", 30: "30分钟", 60: "1小时", }, value: AppSettingsController.instance.autoUpdateFollowDuration.value, onChanged: (e) { AppSettingsController.instance.setAutoUpdateFollowDuration(e); FollowUserService.instance.initTimer(); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.updateFollowThreadFocusNode, autofocus: controller.updateFollowThreadFocusNode.isFoucsed.value, title: "更新线程数", items: const { 1: "1", 2: "2", 3: "3", 4: "4", 6: "6", 8: "8", 10: "10", 12: "12", }, value: AppSettingsController.instance.updateFollowThreadCount.value, onChanged: (e) { AppSettingsController.instance.setUpdateFollowThreadCount(e); }, ), ), ], ); } Widget buildDanmakuSettings() { return ListView( padding: AppStyle.edgeInsetsA48, children: [ Obx( () => SettingsItemWidget( foucsNode: controller.danmakuFoucsNode, autofocus: controller.danmakuFoucsNode.isFoucsed.value, title: "弹幕开关", items: const { 0: "关", 1: "开", }, value: AppSettingsController.instance.danmuEnable.value ? 1 : 0, onChanged: (e) { AppSettingsController.instance.setDanmuEnable(e == 1); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.danmakuSizeFoucsNode, autofocus: controller.danmakuSizeFoucsNode.isFoucsed.value, title: "弹幕大小", items: { 24.0: "24", 32.0: "32", 40.0: "40", 48.0: "48", 56.0: "56", 64.0: "64", 72.0: "72", }, value: AppSettingsController.instance.danmuSize.value, onChanged: (e) { AppSettingsController.instance.setDanmuSize(e); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.danmakuSpeedFoucsNode, autofocus: controller.danmakuSpeedFoucsNode.isFoucsed.value, title: "弹幕速度", items: { 18.0: "很慢", 14.0: "较慢", 12.0: "慢", 10.0: "正常", 8.0: "快", 6.0: "较快", 4.0: "很快", }, value: AppSettingsController.instance.danmuSpeed.value, onChanged: (e) { AppSettingsController.instance.setDanmuSpeed(e); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.danmakuAreaFoucsNode, autofocus: controller.danmakuAreaFoucsNode.isFoucsed.value, title: "显示区域", items: { 0.25: "1/4", 0.5: "1/2", 0.75: "3/4", 1.0: "全屏", }, value: AppSettingsController.instance.danmuArea.value, onChanged: (e) { AppSettingsController.instance.setDanmuArea(e); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.danmakuOpacityFoucsNode, autofocus: controller.danmakuOpacityFoucsNode.isFoucsed.value, title: "不透明度", items: { 0.1: "10%", 0.2: "20%", 0.3: "30%", 0.4: "40%", 0.5: "50%", 0.6: "60%", 0.7: "70%", 0.8: "80%", 0.9: "90%", 1.0: "100%", }, value: AppSettingsController.instance.danmuOpacity.value, onChanged: (e) { AppSettingsController.instance.setDanmuOpacity(e); }, ), ), AppStyle.vGap24, Obx( () => SettingsItemWidget( foucsNode: controller.danmakuStorkeFoucsNode, autofocus: controller.danmakuStorkeFoucsNode.isFoucsed.value, title: "描边宽度", items: { 2.0: "2", 4.0: "4", 6.0: "6", 8.0: "8", 10.0: "10", 12.0: "12", 14.0: "14", 16.0: "16", }, value: AppSettingsController.instance.danmuStrokeWidth.value, onChanged: (e) { AppSettingsController.instance.setDanmuStrokeWidth(e); }, ), ), ], ); } Widget buildAccountSettings() { return ListView( padding: AppStyle.edgeInsetsA48, children: [ Obx( () => HighlightListTile( focusNode: controller.bilibiliFoucsNode, autofocus: controller.bilibiliFoucsNode.isFoucsed.value, title: "哔哩哔哩账号", subtitle: BiliBiliAccountService.instance.logined.value ? "已登录:${BiliBiliAccountService.instance.name.value}" : "未登录,点击登录", leading: Image.asset( "assets/images/bilibili.png", width: 64.w, height: 64.w, ), onTap: controller.bilibiliTap, ), ), AppStyle.vGap24, HighlightListTile( focusNode: AppFocusNode(), title: "斗鱼账号", subtitle: "无需登录", leading: Image.asset( "assets/images/douyu.png", width: 64.w, height: 64.w, ), onTap: () { SmartDialog.showToast("无需登录斗鱼,您可以直接观看直播"); }, ), AppStyle.vGap24, HighlightListTile( focusNode: AppFocusNode(), title: "虎牙账号", subtitle: "无需登录", leading: Image.asset( "assets/images/huya.png", width: 64.w, height: 64.w, ), onTap: () { SmartDialog.showToast("无需登录虎牙,您可以直接观看直播"); }, ), AppStyle.vGap24, HighlightListTile( focusNode: AppFocusNode(), title: "抖音账号", subtitle: "无需登录", leading: Image.asset( "assets/images/douyin.png", width: 64.w, height: 64.w, ), onTap: () { SmartDialog.showToast("无需登录抖音,您可以直接观看直播"); }, ) ], ); } Widget buildAbout() { return ListView( padding: AppStyle.edgeInsetsA48, children: [ HighlightListTile( focusNode: controller.versionFocusNode, title: "版本", subtitle: "v${Utils.packageInfo.version}", onTap: ()=>{}, ), ], ); } } ================================================ FILE: simple_live_tv_app/lib/modules/sync/sync_controller.dart ================================================ import 'dart:async'; import 'dart:convert'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/event_bus.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/models/db/follow_user.dart'; import 'package:simple_live_tv_app/models/db/history.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; import 'package:simple_live_tv_app/services/db_service.dart'; import 'package:simple_live_tv_app/services/signalr_service.dart'; class SyncController extends BaseController { final SignalRService signalR = SignalRService(); StreamSubscription? _stateSubscription; StreamSubscription? _roomDestroyedSubscription; StreamSubscription? _roomUserUpdatedSubscription; StreamSubscription? _onFavoriteSubscription; StreamSubscription? _onHistorySubscription; StreamSubscription? _onShieldWordSubscription; StreamSubscription? _onBiliAccountSubscription; var currentRoomId = "--".obs; RxList roomUsers = [].obs; Timer? _timer; var countDown = 600.obs; Rx state = Rx(SignalRConnectionState.connecting); @override void onInit() { connect(); super.onInit(); } void connect() async { listenSignalR(); await signalR.connect(); if (signalR.state == SignalRConnectionState.connected) { createRoom(); } } void createRoom() async { try { var resp = await signalR.createRoom(); if (resp.isSuccess) { currentRoomId.value = resp.data!; _startTimer(); } else { SmartDialog.showToast(resp.message); Get.back(); } } catch (e) { SmartDialog.showToast("创建房间失败"); Get.back(); } } void _startTimer() { // 倒计时5分钟,自动关闭页面 countDown.value = 600; _timer = Timer.periodic(const Duration(seconds: 1), (timer) { countDown--; if (countDown <= 0) { timer.cancel(); Get.back(); } }); } void listenSignalR() { _stateSubscription = signalR.stateStream.listen((event) { state.value = event; }); _roomDestroyedSubscription = signalR.onRoomDestroyedStream.listen((roomId) { SmartDialog.showToast("房间已被销毁"); Get.back(); }); _roomUserUpdatedSubscription = signalR.onRoomUserUpdatedStream.listen( (roomUsers) { this.roomUsers.assignAll(roomUsers); }, ); _onFavoriteSubscription = signalR.onFavoriteStream.listen((data) { onReceiveFavorite(data.$1, data.$2); }); _onHistorySubscription = signalR.onHistoryStream.listen((data) { onReceiveHistory(data.$1, data.$2); }); _onShieldWordSubscription = signalR.onShieldWordStream.listen((data) { onReceiveShieldWord(data.$1, data.$2); }); _onBiliAccountSubscription = signalR.onBiliAccountStream.listen((data) { onReceiveBiliAccount(data.$1, data.$2); }); } void onReceiveFavorite(bool overlay, String data) async { try { var jsonBody = json.decode(data); if (overlay) { await DBService.instance.followBox.clear(); } for (var item in jsonBody) { var user = FollowUser.fromJson(item); await DBService.instance.followBox.put(user.id, user); } SmartDialog.showToast('已同步关注用户列表'); EventBus.instance.emit(Constant.kUpdateFollow, 0); SmartDialog.showToast("已同步关注列表"); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } void onReceiveHistory(bool overlay, String data) async { try { var jsonBody = json.decode(data); if (overlay) { await DBService.instance.historyBox.clear(); } for (var item in jsonBody) { var history = History.fromJson(item); if (DBService.instance.historyBox.containsKey(history.id)) { var old = DBService.instance.historyBox.get(history.id); //如果本地的更新时间比较新,就不更新 if (old!.updateTime.isAfter(history.updateTime)) { continue; } } await DBService.instance.addOrUpdateHistory(history); } SmartDialog.showToast('已同步历史记录'); EventBus.instance.emit(Constant.kUpdateHistory, 0); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } void onReceiveShieldWord(bool overlay, String data) async { try { var jsonBody = json.decode(data); if (overlay) { AppSettingsController.instance.clearShieldList(); } for (var item in jsonBody) { AppSettingsController.instance.addShieldList(item); } SmartDialog.showToast('已同步屏蔽词'); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } void onReceiveBiliAccount(bool overlay, String data) async { try { var jsonBody = json.decode(data); var cookie = jsonBody['cookie']; BiliBiliAccountService.instance.setCookie(cookie); BiliBiliAccountService.instance.loadUserInfo(); SmartDialog.showToast('已同步哔哩哔哩账号'); } catch (e) { SmartDialog.showToast("同步失败:$e"); Log.logPrint(e); } } @override void onClose() { _timer?.cancel(); _stateSubscription?.cancel(); _roomDestroyedSubscription?.cancel(); _roomUserUpdatedSubscription?.cancel(); _onFavoriteSubscription?.cancel(); _onHistorySubscription?.cancel(); _onShieldWordSubscription?.cancel(); _onBiliAccountSubscription?.cancel(); signalR.dispose(); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/modules/sync/sync_page.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/modules/sync/sync_controller.dart'; import 'package:simple_live_tv_app/services/signalr_service.dart'; import 'package:simple_live_tv_app/services/sync_service.dart'; import 'package:simple_live_tv_app/widgets/app_scaffold.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; class SyncPage extends GetView { const SyncPage({super.key}); @override Widget build(BuildContext context) { return AppScaffold( child: Column( children: [ AppStyle.vGap24, Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ AppStyle.hGap48, HighlightButton( focusNode: AppFocusNode(), iconData: Icons.arrow_back, text: "返回", autofocus: true, onTap: () { Get.back(); }, ), AppStyle.hGap32, Text( "数据同步", style: AppStyle.titleStyleWhite.copyWith( fontSize: 36.w, fontWeight: FontWeight.bold, ), ), const Spacer(), ], ), AppStyle.vGap24, Expanded( child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "远程同步", style: AppStyle.titleStyleWhite.copyWith( fontSize: 32.w, fontWeight: FontWeight.bold, ), ), AppStyle.vGap16, Obx( () => Visibility( visible: SyncService.instance.httpRunning.value, child: GestureDetector( onTap: () { Get.back(); }, child: QrImageView( data: controller.currentRoomId.value, version: QrVersions.auto, backgroundColor: Colors.white, padding: AppStyle.edgeInsetsA24, size: 420.0.w, ), ), ), ), AppStyle.vGap24, Obx( () => Visibility( visible: controller.state.value == SignalRConnectionState.connected, child: Text.rich( TextSpan( text: '房间号:', children: [ TextSpan( text: controller.currentRoomId.value, style: AppStyle.textStyleWhite .copyWith(fontWeight: FontWeight.bold), ) ], ), style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), Obx( () => Visibility( visible: controller.state.value == SignalRConnectionState.disconnected, child: Text( '连接已断开,请尝试重进此页面', style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), Obx( () => Visibility( visible: controller.state.value == SignalRConnectionState.connecting, child: Text( '正在创建房间...', style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), AppStyle.vGap12, Obx( () => Visibility( visible: controller.state.value == SignalRConnectionState.connected, child: Text( "${controller.countDown}秒后将自动关闭服务\n请扫描二维码或输入房间号进行连接", style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), ], ), ), VerticalDivider( color: Colors.white.withAlpha(50), thickness: 2.w, endIndent: 120.w, indent: 120.w, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "局域网同步", style: AppStyle.titleStyleWhite.copyWith( fontSize: 32.w, fontWeight: FontWeight.bold, ), ), AppStyle.vGap16, Obx( () => Visibility( visible: SyncService.instance.httpRunning.value, child: GestureDetector( onTap: () { Get.back(); }, child: QrImageView( data: SyncService.instance.ipAddress.value, version: QrVersions.auto, backgroundColor: Colors.white, padding: AppStyle.edgeInsetsA24, size: 420.0.w, ), ), ), ), AppStyle.vGap24, Obx( () => Visibility( visible: SyncService.instance.httpRunning.value, child: Text( '服务已启动:${SyncService.instance.ipAddress.value.split(';').map((e) => '$e:${SyncService.httpPort}').join(';')}', style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), Obx( () => Visibility( visible: !SyncService.instance.httpRunning.value, child: Text( 'HTTP服务未启动:${SyncService.instance.httpErrorMsg},请尝试重启应用', style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), AppStyle.vGap12, Obx( () => Visibility( visible: SyncService.instance.httpRunning.value, child: Text( "请扫描二维码或输入IP地址进行连接\n建立连接后可在APP端选择需要同步至TV端的数据", style: AppStyle.textStyleWhite, textAlign: TextAlign.center, ), ), ), ], ), ), ], ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/requests/common_request.dart ================================================ import 'dart:convert'; import 'package:simple_live_tv_app/models/version_model.dart'; import 'package:simple_live_tv_app/requests/http_client.dart'; /// 通用的请求 class CommonRequest { Future checkUpdate() async { try { return await checkUpdateGitMirror(); } catch (e) { return await checkUpdateJsDelivr(); } } /// 检查更新 Future checkUpdateGitMirror() async { var result = await HttpClient.instance.getJson( "https://github.iill.moe/xiaoyaocz/dart_simple_live/master/assets/tv_app_version.json", queryParameters: { "ts": DateTime.now().millisecondsSinceEpoch, }, ); if (result is Map) { return VersionModel.fromJson(result as Map); } return VersionModel.fromJson(json.decode(result)); } /// 检查更新 Future checkUpdateJsDelivr() async { var result = await HttpClient.instance.getJson( "https://cdn.jsdelivr.net/gh/xiaoyaocz/dart_simple_live@master/assets/tv_app_version.json", queryParameters: { "ts": DateTime.now().millisecondsSinceEpoch, }, ); if (result is Map) { return VersionModel.fromJson(result as Map); } return VersionModel.fromJson(json.decode(result)); } } ================================================ FILE: simple_live_tv_app/lib/requests/custom_log_interceptor.dart ================================================ import 'package:dio/dio.dart'; import 'package:simple_live_tv_app/app/log.dart'; class CustomLogInterceptor extends Interceptor { @override void onRequest(RequestOptions options, RequestInterceptorHandler handler) { options.extra["ts"] = DateTime.now().millisecondsSinceEpoch; super.onRequest(options, handler); } @override void onError(DioException err, ErrorInterceptorHandler handler) { var time = DateTime.now().millisecondsSinceEpoch - err.requestOptions.extra["ts"]; Log.e('''【HTTP请求错误-${err.type}】 耗时:${time}ms ${err.message} Request Method:${err.requestOptions.method} Response Code:${err.response?.statusCode} Request URL:${err.requestOptions.uri} Request Query:${err.requestOptions.queryParameters} Request Data:${err.requestOptions.data} Request Headers:${err.requestOptions.headers} Response Headers:${err.response?.headers.map} Response Data:${err.response?.data}''', err.stackTrace); super.onError(err, handler); } @override void onResponse(Response response, ResponseInterceptorHandler handler) { var time = DateTime.now().millisecondsSinceEpoch - response.requestOptions.extra["ts"]; Log.i( '''【HTTP请求响应】 耗时:${time}ms Request Method:${response.requestOptions.method} Request Code:${response.statusCode} Request URL:${response.requestOptions.uri} Request Query:${response.requestOptions.queryParameters} Request Data:${response.requestOptions.data} Request Headers:${response.requestOptions.headers} Response Headers:${response.headers.map} Response Data:${response.data}''', ); super.onResponse(response, handler); } } ================================================ FILE: simple_live_tv_app/lib/requests/http_client.dart ================================================ import 'package:dio/dio.dart'; import 'package:simple_live_tv_app/requests/custom_log_interceptor.dart'; import 'package:simple_live_tv_app/requests/http_error.dart'; class HttpClient { static HttpClient? _httpUtil; static HttpClient get instance { _httpUtil ??= HttpClient(); return _httpUtil!; } late Dio dio; HttpClient() { dio = Dio( BaseOptions( connectTimeout: const Duration(seconds: 20), receiveTimeout: const Duration(seconds: 20), sendTimeout: const Duration(seconds: 20), ), ); dio.interceptors.add(CustomLogInterceptor()); } /// Get请求,返回String /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future getText( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.plain, headers: header, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送GET请求失败"); } } } /// Get请求,返回Map /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future getJson( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.json, headers: header, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送GET请求失败"); } } } /// Get请求,返回Response /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future> get( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.get( url, queryParameters: queryParameters, options: Options( responseType: ResponseType.json, headers: header, ), cancelToken: cancel, ); return result; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送GET请求失败"); } } } /// Post请求,返回Map /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [data] 内容 /// * [cancel] 任务取消Token Future postJson( String url, { Map? queryParameters, dynamic data, Map? header, bool formUrlEncoded = false, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; data ??= {}; var result = await dio.post( url, queryParameters: queryParameters, data: data, options: Options( responseType: ResponseType.json, headers: header, contentType: formUrlEncoded ? Headers.formUrlEncodedContentType : null, ), cancelToken: cancel, ); return result.data; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { throw HttpError(e.message ?? "", statusCode: e.response?.statusCode ?? 0); } else { throw HttpError("发送POST请求失败"); } } } /// Head请求,返回Response /// * [url] 请求链接 /// * [queryParameters] 请求参数 /// * [cancel] 任务取消Token Future head( String url, { Map? queryParameters, Map? header, CancelToken? cancel, }) async { try { queryParameters ??= {}; header ??= {}; var result = await dio.head( url, queryParameters: queryParameters, options: Options( headers: header, receiveDataWhenStatusError: true, ), cancelToken: cancel, ); return result; } catch (e) { if (e is DioException && e.type == DioExceptionType.badResponse) { return e.response!; } else { throw HttpError("发送HEAD请求失败"); } } } } ================================================ FILE: simple_live_tv_app/lib/requests/http_error.dart ================================================ class HttpError extends Error { /// 错误码 final int statusCode; /// 错误信息 final String message; HttpError( this.message, { this.statusCode = 0, }); @override String toString() { if (statusCode != 0) { return statusCodeToString(statusCode); } return message; } String statusCodeToString(int statusCode) { switch (statusCode) { case 400: return "错误的请求(400)"; case 401: return "无权限访问资源(401)"; case 403: return "无权限访问资源(403)"; case 404: return "服务器找不到请求的资源(404)"; case 500: return "服务器出现错误(500)"; case 502: return "服务器出现错误(502)"; case 503: return "服务器出现错误(503)"; default: return "连接服务器失败,请稍后再试($statusCode)"; } } } ================================================ FILE: simple_live_tv_app/lib/routes/app_navigation.dart ================================================ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/modules/category/category_controller.dart'; import 'package:simple_live_tv_app/routes/route_path.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; /// APP页面跳转封装 /// * 需要参数的页面都应使用此类 /// * 如不需要参数,可以使用Get.toNamed class AppNavigator { /// 跳转至直播间 static void toLiveRoomDetail( {required Site site, required String roomId}) async { if (site.id == Constant.kBiliBili && !BiliBiliAccountService.instance.logined.value && AppSettingsController.instance.bilibiliLoginTip.value) { await toBiliBiliLogin(); if (!BiliBiliAccountService.instance.logined.value) { SmartDialog.showToast("未完成登录"); return; } } Get.toNamed(RoutePath.kLiveRoomDetail, arguments: site, parameters: { "roomId": roomId, }); } /// 跳转至哔哩哔哩登录 static Future toBiliBiliLogin() async { await Get.toNamed(RoutePath.kBiliBiliQRLogin); } /// 跳转至分类详情 static void toCategoryDetail( {required Site site, required LiveSubCategoryExt category}) { Get.toNamed(RoutePath.kCategoryDetail, arguments: [site, category]); } } ================================================ FILE: simple_live_tv_app/lib/routes/app_pages.dart ================================================ // ignore_for_file: prefer_inlined_adds import 'package:get/get.dart'; import 'package:simple_live_tv_app/modules/account/bilibili/qr_login_controller.dart'; import 'package:simple_live_tv_app/modules/account/bilibili/qr_login_page.dart'; import 'package:simple_live_tv_app/modules/agreement/agreement_page.dart'; import 'package:simple_live_tv_app/modules/category/category_controller.dart'; import 'package:simple_live_tv_app/modules/category/category_page.dart'; import 'package:simple_live_tv_app/modules/category/detail/category_detail_controller.dart'; import 'package:simple_live_tv_app/modules/category/detail/category_detail_page.dart'; import 'package:simple_live_tv_app/modules/follow_user/follow_user_page.dart'; import 'package:simple_live_tv_app/modules/history/history_controller.dart'; import 'package:simple_live_tv_app/modules/history/history_page.dart'; import 'package:simple_live_tv_app/modules/home/home_controller.dart'; import 'package:simple_live_tv_app/modules/home/home_page.dart'; import 'package:simple_live_tv_app/modules/hot_live/hot_live_controller.dart'; import 'package:simple_live_tv_app/modules/hot_live/hot_live_page.dart'; import 'package:simple_live_tv_app/modules/live_room/live_room_controller.dart'; import 'package:simple_live_tv_app/modules/live_room/live_room_page.dart'; import 'package:simple_live_tv_app/modules/search/anchor/search_anchor_controller.dart'; import 'package:simple_live_tv_app/modules/search/anchor/search_anchor_page.dart'; import 'package:simple_live_tv_app/modules/search/room/search_room_controller.dart'; import 'package:simple_live_tv_app/modules/search/room/search_room_page.dart'; import 'package:simple_live_tv_app/modules/settings/settings_controller.dart'; import 'package:simple_live_tv_app/modules/settings/settings_page.dart'; import 'package:simple_live_tv_app/modules/sync/sync_controller.dart'; import 'package:simple_live_tv_app/modules/sync/sync_page.dart'; import 'route_path.dart'; class AppPages { AppPages._(); static final routes = [ GetPage( name: RoutePath.kAgreement, page: () => const AgreementPage(), ), // 首页 GetPage( name: RoutePath.kHome, page: () => const HomePage(), bindings: [ BindingsBuilder.put(() => HomeController()), ], ), // 数据同步 GetPage( name: RoutePath.kSync, page: () => const SyncPage(), bindings: [ BindingsBuilder.put(() => SyncController()), ], ), // 关注 GetPage( name: RoutePath.kFollow, page: () => const FollowUserPage(), ), //直播间 GetPage( name: RoutePath.kLiveRoomDetail, page: () => const LiveRoomPage(), binding: BindingsBuilder.put( () => LiveRoomController( pSite: Get.arguments, pRoomId: Get.parameters["roomId"] ?? "", ), ), ), //哔哩哔哩二维码登录 GetPage( name: RoutePath.kBiliBiliQRLogin, page: () => const BiliBiliQRLoginPage(), bindings: [ BindingsBuilder.put(() => BiliBiliQRLoginController()), ], ), // 设置 GetPage( name: RoutePath.kSettings, page: () => const SettingsPage(), bindings: [ BindingsBuilder.put(() => SettingsController()), ], ), // 历史记录 GetPage( name: RoutePath.kHistory, page: () => const HistoryPage(), bindings: [ BindingsBuilder.put(() => HistoryController()), ], ), //热门直播 GetPage( name: RoutePath.kHotLive, page: () => const HotLivePage(), bindings: [ BindingsBuilder.put(() => HotliveController()), ], ), //分类 GetPage( name: RoutePath.kCategory, page: () => const CategoryPage(), bindings: [ BindingsBuilder.put(() => CategoryController()), ], ), //分类 GetPage( name: RoutePath.kCategoryDetail, page: () => const CategoryDetailPage(), binding: BindingsBuilder.put( () => CategoryDetailController( site: Get.arguments[0], subCategory: Get.arguments[1], ), ), ), // 搜索房间 GetPage( name: RoutePath.kSearchRoom, page: () => const SearchRoomPage(), bindings: [ BindingsBuilder.put( () => SearchRoomController( Get.arguments, ), ), ], ), // 搜索主播 GetPage( name: RoutePath.kSearchAnchor, page: () => const SearchAnchorPage(), bindings: [ BindingsBuilder.put( () => SearchAnchorController( Get.arguments, ), ), ], ), ]; } ================================================ FILE: simple_live_tv_app/lib/routes/route_path.dart ================================================ /// 路由路径 class RoutePath { /// 用户协议 static const kAgreement = "/agreement"; /// 首页 static const kHome = "/home"; /// 数据同步 static const kSync = "/sync"; /// 搜索房间 static const kSearchRoom = "/search/room"; /// 搜索主播 static const kSearchAnchor = "/search/anchor"; /// 关注 static const kFollow = "/follow"; /// 历史记录 static const kHistory = "/history"; /// 直播间 static const kLiveRoomDetail = "/room/detail"; /// 哔哩哔哩登录 static const kBiliBiliQRLogin = "/bilibili/qr_login"; /// 设置 static const kSettings = "/settings"; /// 热门直播 static const kHotLive = "/hot_live"; /// 分类 static const kCategory = "/category"; /// 分类详情 static const kCategoryDetail = "/category/detail"; } ================================================ FILE: simple_live_tv_app/lib/services/bilibili_account_service.dart ================================================ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:simple_live_core/simple_live_core.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/models/account/bilibili_user_info_page.dart'; import 'package:simple_live_tv_app/requests/http_client.dart'; import 'package:simple_live_tv_app/services/local_storage_service.dart'; class BiliBiliAccountService extends GetxService { static BiliBiliAccountService get instance => Get.find(); var logined = false.obs; var cookie = ""; var uid = 0; var name = "未登录".obs; @override void onInit() { cookie = LocalStorageService.instance .getValue(LocalStorageService.kBilibiliCookie, ""); logined.value = cookie.isNotEmpty; loadUserInfo(); super.onInit(); } Future loadUserInfo() async { if (cookie.isEmpty) { return; } try { var result = await HttpClient.instance.getJson( "https://api.bilibili.com/x/member/web/account", header: { "Cookie": cookie, }, ); if (result["code"] == 0) { var info = BiliBiliUserInfoModel.fromJson(result["data"]); name.value = info.uname ?? "未登录"; uid = info.mid ?? 0; setSite(); } else { SmartDialog.showToast("哔哩哔哩登录已失效,请重新登录"); logout(); } } catch (e) { SmartDialog.showToast("获取哔哩哔哩用户信息失败,可前往账号管理重试"); } } void setSite() { var site = (Sites.allSites[Constant.kBiliBili]!.liveSite as BiliBiliSite); site.userId = uid; site.cookie = cookie; } void setCookie(String cookie) { this.cookie = cookie; LocalStorageService.instance .setValue(LocalStorageService.kBilibiliCookie, cookie); logined.value = cookie.isNotEmpty; } void logout() async { cookie = ""; uid = 0; name.value = "未登录"; setSite(); LocalStorageService.instance .setValue(LocalStorageService.kBilibiliCookie, ""); logined.value = false; } } ================================================ FILE: simple_live_tv_app/lib/services/db_service.dart ================================================ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:simple_live_tv_app/models/db/follow_user.dart'; import 'package:simple_live_tv_app/models/db/history.dart'; class DBService extends GetxService { static DBService get instance => Get.find(); late Box historyBox; late Box followBox; Future init() async { historyBox = await Hive.openBox("TVHostiry"); followBox = await Hive.openBox("TVFollowUser"); } bool getFollowExist(String id) { return followBox.containsKey(id); } List getFollowList() { return followBox.values.toList(); } Future addFollow(FollowUser follow) async { await followBox.put(follow.id, follow); } Future deleteFollow(String id) async { await followBox.delete(id); } History? getHistory(String id) { if (historyBox.containsKey(id)) { return historyBox.get(id); } return null; } Future addOrUpdateHistory(History history) async { await historyBox.put(history.id, history); } List getHistores() { var his = historyBox.values.toList(); his.sort((a, b) => b.updateTime.compareTo(a.updateTime)); return his; } } ================================================ FILE: simple_live_tv_app/lib/services/follow_user_service.dart ================================================ import 'dart:async'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/app/event_bus.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/models/db/follow_user.dart'; import 'package:simple_live_tv_app/services/db_service.dart'; class FollowUserService extends BasePageController { static FollowUserService get instance => Get.find(); StreamSubscription? subscription; RxList livingList = RxList(); Timer? updateTimer; bool needUpdate = true; @override void onInit() { subscription = EventBus.instance.listen(Constant.kUpdateFollow, (p0) { needUpdate = false; refreshData(); }); if (list.isEmpty) { refreshData(); } initTimer(); super.onInit(); } void initTimer() { if (AppSettingsController.instance.autoUpdateFollowEnable.value) { updateTimer?.cancel(); updateTimer = Timer.periodic( Duration( minutes: AppSettingsController.instance.autoUpdateFollowDuration.value, ), (timer) { Log.logPrint("Update Follow Timer"); refreshData(); }, ); } else { updateTimer?.cancel(); } } var updatedCount = 0; var updating = false.obs; @override Future> getData(int page, int pageSize) async { if (page > 1) { return []; } var followList = DBService.instance.getFollowList(); if (needUpdate) { startUpdateStatus(followList); } needUpdate = true; if (followList.isEmpty) { updating.value = false; } return followList; } void sortList() { list.sort((a, b) => b.liveStatus.value.compareTo(a.liveStatus.value)); updateLivingList(); } void updateLivingList() { livingList.assignAll(list.where((x) => x.liveStatus.value == 2)); } void startUpdateStatus(List followList) async { updatedCount = 0; updating.value = true; var threadCount = AppSettingsController.instance.updateFollowThreadCount.value; var tasks = []; for (var i = 0; i < threadCount; i++) { tasks.add( Future(() async { var start = i * followList.length ~/ threadCount; var end = (i + 1) * followList.length ~/ threadCount; // 确保 end 不超出列表长度 if (end > followList.length) { end = followList.length; } var items = followList.sublist(start, end); for (var item in items) { await updateLiveStatus(item); } }), ); } await Future.wait(tasks); } Future updateLiveStatus(FollowUser item) async { try { var site = Sites.allSites[item.siteId]!; item.liveStatus.value = (await site.liveSite.getLiveStatus(roomId: item.roomId)) ? 2 : 1; //sortList(); //updateLivingList(); } catch (e) { Log.logPrint(e); } finally { updatedCount++; if (updatedCount >= list.length) { sortList(); updating.value = false; } } } void removeItem(FollowUser item, {bool refresh = true}) async { var result = await Utils.showAlertDialog("确定要取消关注${item.userName}吗?", title: "取消关注"); if (!result) { return; } await DBService.instance.followBox.delete(item.id); if (refresh) { refreshData(); } else { list.remove(item); livingList.remove(item); } } @override void onClose() { updateTimer?.cancel(); subscription?.cancel(); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/services/local_storage_service.dart ================================================ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:simple_live_tv_app/app/log.dart'; class LocalStorageService extends GetxService { static LocalStorageService get instance => Get.find(); /// 首次运行 static const String kFirstRun = "FirstRun"; /// 缩放模式 static const String kPlayerScaleMode = "ScaleMode"; /// 网站排序 static const String kSiteSort = "SiteSort"; /// 首页排序 static const String kHomeSort = "HomeSort"; /// 显示模式 /// * [0] 跟随系统 /// * [1] 浅色模式 /// * [2] 深色模式 static const String kThemeMode = "ThemeMode"; /// DEBUG模式 static const String kDebugModeKey = "DebugMode"; /// 弹幕大小 static const String kDanmuSize = "DanmuSize"; /// 弹幕速度 static const String kDanmuSpeed = "DanmuSpeed"; /// 弹幕区域 static const String kDanmuArea = "DanmuArea"; /// 弹幕透明度 static const String kDanmuOpacity = "DanmuOpacity"; /// 弹幕描边大小 static const String kDanmuStrokeWidth = "DanmuStrokeWidth"; /// 弹幕-屏蔽滚动 static const String kDanmuHideScroll = "DanmuHideScroll"; /// 弹幕-屏蔽底部 static const String kDanmuHideBottom = "DanmuHideBottom"; /// 弹幕-屏蔽顶部 static const String kDanmuHideTop = "DanmuHideTop"; /// 弹幕-顶部边距 static const String kDanmuTopMargin = "DanmuTopMargin"; /// 弹幕-底部边距 static const String kDanmuBottomMargin = "DanmuBottomMargin"; /// 弹幕开启 static const String kDanmuEnable = "DanmuEnable"; /// 硬件解码 static const String kHardwareDecode = "HardwareDecode"; /// 聊天区文字大小 static const String kChatTextSize = "ChatTextSize"; /// 聊天区间隔 static const String kChatTextGap = "ChatTextGap"; /// 聊天区-气泡样式 static const String kChatBubbleStyle = "ChatBubbleStyle"; /// 播放清晰度,0=低,1=中,2=高 static const String kQualityLevel = "QualityLevel"; /// 蜂窝网络下播放清晰度,0=低,1=中,2=高 static const String kQualityLevelCellular = "QualityLevelCellular"; /// 开启定时关闭 static const String kAutoExitEnable = "AutoExitEnable"; /// 定时关闭时间(分钟) static const String kAutoExitDuration = "AutoExitDuration"; /// 房间内定时关闭时间(分钟) /// 需要一个不同的 key,因为用户在房间内设置的倒计时和全局的可能不同。 static const String kRoomAutoExitDuration = "RoomAutoExitDuration"; /// 播放器兼容模式 static const String kPlayerCompatMode = "PlayerCompatMode"; /// 播放器后台自动暂停 static const String kPlayerAutoPause = "PlayerAutoPause"; /// 播放器缓冲区大小 static const String kPlayerBufferSize = "PlayerBufferSize"; /// 自动全屏 static const String kAutoFullScreen = "AutoFullScreen"; /// 小窗隐藏弹幕 static const String kPIPHideDanmu = "PIPHideDanmu"; /// 哔哩哔哩cookie static const String kBilibiliCookie = "BilibiliCookie"; ///主题色 static const String kStyleColor = "kStyleColor"; ///动态取色 static const String kIsDynamic = "kIsDynamic"; /// 提示哔哩哔哩登录 static const String kBilibiliLoginTip = "BilibiliLoginTip"; /// 开启自动更新关注 static const String kAutoUpdateFollowEnable = "AutoUpdateFollowEnable"; /// 定时自动更新关注间隔(分钟) static const String kUpdateFollowDuration = "AutoUpdateFollowDuration"; /// 开启多线程更新关注 static const String kUpdateFollowThreadCount = "UpdateFollowThreadCount"; late Box settingsBox; late Box shieldBox; Future init() async { settingsBox = await Hive.openBox( "TVLocalStorage", ); shieldBox = await Hive.openBox( "TVDanmuShield", ); } T getValue(dynamic key, T defaultValue) { try { var value = settingsBox.get(key, defaultValue: defaultValue) as T; Log.d("Get LocalStorage:$key\r\n$value"); return value; } catch (e) { Log.logPrint(e); return defaultValue; } } Future setValue(dynamic key, T value) async { Log.d("Set LocalStorage:$key\r\n$value"); return await settingsBox.put(key, value); } Future removeValue(dynamic key) async { Log.d("Remove LocalStorage:$key"); return await settingsBox.delete(key); } } ================================================ FILE: simple_live_tv_app/lib/services/signalr_service.dart ================================================ import 'dart:async'; import 'package:signalr_netcore/signalr_client.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/app/utils.dart'; enum SignalRConnectionState { connecting, connected, disconnected, } class SignalRService { static const String kUrl = "https://sync1.nsapps.cn/sync"; SignalRConnectionState state = SignalRConnectionState.connecting; final _stateStreamController = StreamController.broadcast(); Stream get stateStream => _stateStreamController.stream; final _onFavoriteStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onFavoriteStream => _onFavoriteStreamController.stream; final _onHistoryStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onHistoryStream => _onHistoryStreamController.stream; final _onShieldWordStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onShieldWordStream => _onShieldWordStreamController.stream; final _onBiliAccountStreamController = StreamController<(bool, String)>.broadcast(); Stream<(bool, String)> get onBiliAccountStream => _onBiliAccountStreamController.stream; final _onRoomDestroyedStreamController = StreamController.broadcast(); Stream get onRoomDestroyedStream => _onRoomDestroyedStreamController.stream; final _onRoomUserUpdatedStreamController = StreamController>.broadcast(); Stream> get onRoomUserUpdatedStream => _onRoomUserUpdatedStreamController.stream; HubConnection? hubConnection; Future connect() async { hubConnection = HubConnectionBuilder().withUrl(kUrl).build(); hubConnection!.onclose(({Exception? error}) { state = SignalRConnectionState.disconnected; _stateStreamController.add(state); }); hubConnection!.onreconnected(({String? connectionId}) { Log.d("reconnected: $connectionId"); state = SignalRConnectionState.connected; _stateStreamController.add(state); }); await hubConnection!.start(); state = SignalRConnectionState.connected; _stateStreamController.add(state); _listen(); } void _listen() { hubConnection?.on("onFavoriteReceived", (args) { _onFavoriteStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onHistoryReceived", (args) { _onHistoryStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onShieldWordReceived", (args) { _onShieldWordStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onBiliAccountReceived", (args) { _onBiliAccountStreamController.add((args![0] as bool, args[1] as String)); }); hubConnection?.on("onRoomDestroyed", (args) { _onRoomDestroyedStreamController.add(args![0].toString()); }); hubConnection?.on("onUserUpdated", (args) { var list = (args![0] as List).map((e) => RoomUser.fromObject(e)).toList(); _onRoomUserUpdatedStreamController.add(list); }); } Future disconnect() async { await hubConnection?.stop(); state = SignalRConnectionState.disconnected; _stateStreamController.add(state); } Future> createRoom() async { if (state != SignalRConnectionState.connected) { throw Exception("not connected"); } String app = "Simple Live TV"; String platform = 'tv'; String version = Utils.packageInfo.version; var resp = await hubConnection ?.invoke("CreateRoom", args: [app, platform, version]); return Resp.fromObject(resp); } Future joinRoom(String roomId) async { if (state != SignalRConnectionState.connected) { throw Exception("not connected"); } String app = "Simple Live TV"; String platform = 'tv'; String version = Utils.packageInfo.version; var resp = await hubConnection ?.invoke("JoinRoom", args: [roomId, app, platform, version]); return Resp.fromObject(resp); } Future sendContent({ required String roomName, required String action, required bool overlay, required String content, }) async { if (state != SignalRConnectionState.connected) { throw Exception("not connected"); } var resp = await hubConnection?.invoke(action, args: [roomName, overlay, content]); return Resp.fromObject(resp); } void dispose() { _stateStreamController.close(); _onFavoriteStreamController.close(); _onHistoryStreamController.close(); _onShieldWordStreamController.close(); _onBiliAccountStreamController.close(); _onRoomDestroyedStreamController.close(); _onRoomUserUpdatedStreamController.close(); hubConnection?.stop(); } } class Resp { final bool isSuccess; final String message; final T? data; Resp(this.isSuccess, this.message, this.data); factory Resp.fromJson(Map json) { return Resp( json['isSuccess'], json['message'] ?? "", json['data'], ); } factory Resp.fromObject(Object? obj) { if (obj is Map) { return Resp.fromJson(obj); } return Resp(false, "unknown", null); } } class RoomUser { final String connectionId; final String shortId; final String platform; final String version; final String app; final bool? isCreator; RoomUser({ required this.connectionId, required this.shortId, required this.platform, required this.version, required this.app, this.isCreator = false, }); factory RoomUser.fromJson(Map json) { return RoomUser( connectionId: json['connectionId'], shortId: json['shortId'], platform: json['platform'], version: json['version'], app: json['app'], isCreator: json['isCreator'], ); } factory RoomUser.fromObject(Object? obj) { if (obj is Map) { return RoomUser.fromJson(obj); } return RoomUser( connectionId: "", shortId: "", platform: "", version: "", app: "", ); } } ================================================ FILE: simple_live_tv_app/lib/services/sync_service.dart ================================================ import 'dart:convert'; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:simple_live_tv_app/app/constant.dart'; import 'package:simple_live_tv_app/app/controller/app_settings_controller.dart'; import 'package:simple_live_tv_app/app/event_bus.dart'; import 'package:simple_live_tv_app/app/log.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/models/db/follow_user.dart'; import 'package:simple_live_tv_app/models/db/history.dart'; import 'package:simple_live_tv_app/services/bilibili_account_service.dart'; import 'package:simple_live_tv_app/services/db_service.dart'; import 'package:udp/udp.dart'; import 'package:shelf/shelf.dart' as shelf; import 'package:shelf/shelf_io.dart' as shelf_io; import 'package:shelf_router/shelf_router.dart'; import 'package:uuid/uuid.dart'; class SyncService extends GetxService { static SyncService get instance => Get.find(); UDP? udp; static const int udpPort = 23235; static const int httpPort = 23234; DeviceInfoPlugin deviceInfo = DeviceInfoPlugin(); NetworkInfo networkInfo = NetworkInfo(); HttpServer? server; var ipAddress = "".obs; var httpRunning = false.obs; var httpErrorMsg = "".obs; var deviceId = ""; @override void onInit() { Log.d('SyncService init'); deviceId = (const Uuid().v4()).split('-').first; listenUDP(); initServer(); super.onInit(); } /// 监听来自其他客户端的UDP广播 /// - 如果收到广播,回复自己的信息 void listenUDP() async { udp = await UDP.bind(Endpoint.any(port: const Port(udpPort))); udp!.asStream().listen((datagram) { var str = String.fromCharCodes(datagram!.data); Log.i("Received: $str from ${datagram.address}:${datagram.port}"); if (str.startsWith('{') && str.endsWith('}')) { var data = json.decode(str); //处理Hello的广播 if (data["type"] == "hello") { //如果http服务已经启动,就回复自己的信息 if (httpRunning.value) { sendInfo(); } return; } } else if (str == 'Who is SimpleLive?') { //如果http服务已经启动,就回复自己的信息 if (httpRunning.value) { sendInfo(); } } }); } /// 发送自己的信息 void sendInfo() async { //var ip = await getLocalIP(); var name = await getDeviceName(); var data = { "id": deviceId, "type": "tv", "name": name, //"address": ip, //"port": httpPort, }; await udp!.send( json.encode(data).codeUnits, Endpoint.broadcast( port: const Port(udpPort), ), ); Log.i("send udp info: $data"); } /// 读取本地IP /// - 如果是wifi,直接获取wifi的IP /// - 如果是有线,获取所有的IP,找到全部的IP Future getLocalIP() async { var ip = await networkInfo.getWifiIP(); if (ip == null || ip.isEmpty) { var interfaces = await NetworkInterface.list(); var ipList = []; for (var interface in interfaces) { for (var addr in interface.addresses) { if (addr.type.name == 'IPv4' && !addr.address.startsWith('127') && !addr.isMulticast && !addr.isLoopback) { ipList.add(addr.address); break; } } } ip = ipList.join(';'); } return ip; } Future getDeviceName() async { var name = "SimpleLive-TV"; if (Platform.isAndroid) { var info = await deviceInfo.androidInfo; name = info.model; } else if (Platform.isIOS) { var info = await deviceInfo.iosInfo; name = info.name; } else if (Platform.isMacOS) { var info = await deviceInfo.macOsInfo; name = info.computerName; } else if (Platform.isLinux) { var info = await deviceInfo.linuxInfo; name = info.name; } else if (Platform.isWindows) { var info = await deviceInfo.windowsInfo; name = info.userName; } return name; } /// 初始化HTTP服务 void initServer() async { try { var serverRouter = Router(); serverRouter.get('/', _helloRequest); serverRouter.get('/info', _infoRequest); serverRouter.post('/sync/follow', _syncFollowUserReuqest); serverRouter.post('/sync/history', _syncHistoryReuqest); serverRouter.post('/sync/blocked_word', _syncBlockedWordReuqest); serverRouter.post('/sync/account/bilibili', _syncBiliAccountReuqest); var server = await shelf_io.serve( serverRouter, InternetAddress.anyIPv4, httpPort, ); // Enable content compression server.autoCompress = true; httpRunning.value = true; var ip = await getLocalIP(); ipAddress.value = ip; Log.d('Serving at http://$ip:${server.port}'); } catch (e) { httpErrorMsg.value = e.toString(); Log.logPrint(e); } } /// 测试服务能否正常访问 shelf.Response _helloRequest(shelf.Request request) { return toJsonResponse({ 'status': true, 'message': 'http server is running...', "version": 'SimpeLive ${Platform.operatingSystem} v${Utils.packageInfo.version}', }); } /// 发送自己的信息 Future _infoRequest(shelf.Request request) async { var name = await getDeviceName(); return toJsonResponse({ "id": deviceId, 'type': 'tv', 'name': name, 'version': Utils.packageInfo.version, 'address': ipAddress.value, 'port': httpPort, }); } /// 同步关注用户列表 Future _syncFollowUserReuqest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncFollowUserReuqest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { await DBService.instance.followBox.clear(); } for (var item in jsonBody) { var user = FollowUser.fromJson(item); await DBService.instance.followBox.put(user.id, user); } SmartDialog.showToast('已同步关注用户列表'); EventBus.instance.emit(Constant.kUpdateFollow, 0); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步观看记录 Future _syncHistoryReuqest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncFollowUserReuqest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { await DBService.instance.historyBox.clear(); } for (var item in jsonBody) { var history = History.fromJson(item); if (DBService.instance.historyBox.containsKey(history.id)) { var old = DBService.instance.historyBox.get(history.id); //如果本地的更新时间比较新,就不更新 if (old!.updateTime.isAfter(history.updateTime)) { continue; } } await DBService.instance.addOrUpdateHistory(history); } SmartDialog.showToast('已同步观看记录'); EventBus.instance.emit(Constant.kUpdateHistory, 0); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步弹幕屏蔽词 Future _syncBlockedWordReuqest(shelf.Request request) async { try { var overlay = int.parse(request.requestedUri.queryParameters['overlay'] ?? '0'); var body = await request.readAsString(); Log.d('_syncBlockedWordReuqest: $body'); var jsonBody = json.decode(body); if (overlay == 1) { AppSettingsController.instance.clearShieldList(); } for (var keyword in jsonBody) { AppSettingsController.instance.addShieldList(keyword.trim()); } SmartDialog.showToast('已同步弹幕屏蔽词'); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } /// 同步哔哩哔哩账号 Future _syncBiliAccountReuqest(shelf.Request request) async { try { var body = await request.readAsString(); Log.d('_syncBiliAccountReuqest: $body'); var jsonBody = json.decode(body); var cookie = jsonBody['cookie']; BiliBiliAccountService.instance.setCookie(cookie); BiliBiliAccountService.instance.loadUserInfo(); SmartDialog.showToast('已同步哔哩哔哩账号'); return toJsonResponse({ 'status': true, 'message': 'success', }); } catch (e) { return toJsonResponse({ 'status': false, 'message': e.toString(), }); } } shelf.Response toJsonResponse(Map data) { return shelf.Response.ok( json.encode(data), headers: { 'Content-Type': 'application/json', }, encoding: Encoding.getByName('utf-8'), ); } @override void onClose() { Log.d('SyncService close'); udp?.close(); server?.close(force: true); super.onClose(); } } ================================================ FILE: simple_live_tv_app/lib/widgets/app_scaffold.dart ================================================ import 'package:flutter/material.dart'; class AppScaffold extends StatelessWidget { final Widget child; const AppScaffold({required this.child, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: [ Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [ // //linear-gradient(135deg,#152331,#000000) // Color.fromARGB(255, 29, 50, 70), // Color.fromARGB(255, 14, 21, 29), // Color.fromARGB(255, 29, 50, 70), // linear-gradient(135deg,#141e30,#243b55) Color(0xff141e30), Color(0xff243b55), Color(0xff141e30), ], ), ), ), Positioned.fill(child: child), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/button/highlight_button.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; class HighlightButton extends StatelessWidget { final String text; final IconData? iconData; final Widget? icon; final AppFocusNode focusNode; final Function()? onTap; final bool autofocus; final bool selected; const HighlightButton({ this.iconData, required this.text, this.icon, this.onTap, required this.focusNode, this.autofocus = false, this.selected = false, super.key, }); @override Widget build(BuildContext context) { return Obx( () => HighlightWidget( focusNode: focusNode, borderRadius: AppStyle.radius32, color: Colors.white10, onTap: onTap, autofocus: autofocus, selected: selected, child: Container( height: 64.w, //width: 64.w, padding: AppStyle.edgeInsetsH24, decoration: BoxDecoration( borderRadius: AppStyle.radius32, ), child: Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ buildIcon(), Text( text, style: TextStyle( fontSize: 28.w, color: (focusNode.isFoucsed.value || selected) ? Colors.black : Colors.white, ), ), ], ), ), ), ); } Widget buildIcon() { if (icon != null || iconData != null) { return Padding( padding: AppStyle.edgeInsetsR12, child: icon ?? Icon( iconData, size: 40.w, color: (focusNode.isFoucsed.value || selected) ? Colors.black : Colors.white, ), ); } return const SizedBox(); } } ================================================ FILE: simple_live_tv_app/lib/widgets/button/highlight_list_tile.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; class HighlightListTile extends StatelessWidget { final String title; final String? subtitle; final Widget? leading; final Widget? trailing; final AppFocusNode focusNode; final Function()? onTap; final bool autofocus; const HighlightListTile({ this.subtitle, required this.title, this.leading, this.onTap, required this.focusNode, this.autofocus = false, this.trailing, super.key, }); @override Widget build(BuildContext context) { return Obx( () => IconTheme( data: IconThemeData( color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), child: HighlightWidget( onTap: onTap, autofocus: autofocus, focusNode: focusNode, borderRadius: AppStyle.radius16, child: Padding( padding: AppStyle.edgeInsetsA24, child: Row( children: [ if (leading != null) leading!, if (leading != null) AppStyle.hGap32, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Text( title, style: focusNode.isFoucsed.value ? AppStyle.textStyleBlack : AppStyle.textStyleWhite, ), if (subtitle != null) Text( subtitle!, style: focusNode.isFoucsed.value ? AppStyle.textStyleBlack.copyWith(fontSize: 24.w) : AppStyle.textStyleWhite .copyWith(fontSize: 24.w), ), ], ), ), AppStyle.hGap12, if (onTap != null && focusNode.isFoucsed.value && trailing == null) Icon( Icons.chevron_right, size: 40.w, color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), if (trailing != null) trailing!, ], ), ), ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/button/home_big_button.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; class HomeBigButton extends StatelessWidget { final String text; final IconData iconData; final AppFocusNode focusNode; final Function()? onTap; final bool autofocus; const HomeBigButton({ required this.iconData, required this.text, this.onTap, required this.focusNode, this.autofocus = false, super.key, }); @override Widget build(BuildContext context) { return Obx( () => HighlightWidget( onTap: onTap, autofocus: autofocus, focusNode: focusNode, borderRadius: AppStyle.radius16, color: Colors.white10, child: Container( padding: AppStyle.edgeInsetsA32.copyWith(left: 48.w, right: 48.w), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: AppStyle.edgeInsetsA12, decoration: const BoxDecoration( shape: BoxShape.circle, ), child: Icon( iconData, size: 64.w, color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), ), AppStyle.vGap24, Text( text, style: TextStyle( fontSize: 36.w, color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), ), ], ), ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/card/anchor_card.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/sites.dart'; import 'package:simple_live_tv_app/routes/app_navigation.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; import 'package:simple_live_tv_app/widgets/net_image.dart'; class AnchorCard extends StatelessWidget { final String siteId; final String face; final String name; final String roomId; final int liveStatus; final bool autofocus; final Function()? onTap; final AppFocusNode? focusNode; const AnchorCard({ required this.face, required this.siteId, required this.name, required this.liveStatus, required this.roomId, this.autofocus = false, this.focusNode, this.onTap, super.key, }); @override Widget build(BuildContext context) { var site = Sites.allSites[siteId]!; var focusNode = this.focusNode ?? AppFocusNode(); return Obx( () => HighlightWidget( onTap: onTap ?? () { AppNavigator.toLiveRoomDetail(site: site, roomId: roomId); }, focusNode: focusNode, autofocus: autofocus, borderRadius: AppStyle.radius16, color: Colors.white10, child: Stack( children: [ Padding( padding: AppStyle.edgeInsetsA20, child: Row( mainAxisSize: MainAxisSize.max, children: [ NetImage( face, width: 100.w, height: 100.w, borderRadius: 100.w, cacheWidth: 100, ), AppStyle.hGap16, Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( name, style: TextStyle( fontSize: 36.w, overflow: TextOverflow.ellipsis, color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), ), Text.rich( TextSpan( children: [ WidgetSpan( child: Image.asset( site.logo, width: 32.w, ), ), TextSpan( text: " ${site.name}", ), ], ), style: TextStyle( fontSize: 24.w, color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), ), ], ), ), ], ), ), if (liveStatus == 2) Positioned( right: 0, top: 0, child: Container( padding: AppStyle.edgeInsetsH16.copyWith(top: 4.w, bottom: 4.w), decoration: BoxDecoration( color: Colors.green, borderRadius: BorderRadius.only( topRight: Radius.circular(12.w), bottomLeft: Radius.circular(12.w), ), ), child: Text( "直播中", style: TextStyle( fontSize: 24.w, color: Colors.white, ), ), ), ), ], ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/card/live_room_card.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/app/utils.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; import 'package:simple_live_tv_app/widgets/net_image.dart'; import 'package:marquee/marquee.dart'; class LiveRoomCard extends StatelessWidget { final String cover; final String title; final String anchor; final String roomId; final int online; final bool autofocus; final AppFocusNode focusNode; final Function()? onTap; const LiveRoomCard({ required this.cover, required this.title, required this.anchor, required this.roomId, required this.focusNode, required this.online, this.autofocus = false, this.onTap, super.key, }); @override Widget build(BuildContext context) { return HighlightWidget( focusNode: focusNode, color: Colors.white10, onTap: onTap, borderRadius: AppStyle.radius16, child: Obx( () => Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ClipRRect( borderRadius: BorderRadius.only( topLeft: Radius.circular(16.w), topRight: Radius.circular(16.w), ), child: Stack( children: [ AspectRatio( aspectRatio: 16 / 9, child: NetImage( cover, cacheWidth: 400, ), ), Positioned( right: 8.w, top: 8.w, child: Container( padding: AppStyle.edgeInsetsH8.copyWith(top: 4.w, bottom: 4.w), decoration: BoxDecoration( color: focusNode.isFoucsed.value ? Colors.white : Colors.black54, borderRadius: AppStyle.radius8, ), child: Text.rich( TextSpan( text: "", children: [ WidgetSpan( alignment: PlaceholderAlignment.middle, child: Padding( padding: AppStyle.edgeInsetsR8, child: Icon( Icons.whatshot, color: focusNode.isFoucsed.value ? Colors.orange : Colors.white, size: 20.w, ), ), ), TextSpan( text: Utils.onlineToString(online), ), ], ), style: TextStyle( fontSize: 20.w, color: focusNode.isFoucsed.value ? Colors.black : Colors.white, ), ), ), ), ], ), // child: Container( // height: 200.w, // ), ), AppStyle.vGap8, Padding( padding: AppStyle.edgeInsetsH20, child: SizedBox( height: 56.w, child: focusNode.isFoucsed.value ? Marquee( text: title, style: AppStyle.textStyleBlack, startAfter: const Duration(seconds: 1), velocity: 20, blankSpace: 200.w, //decelerationDuration: const Duration(seconds: 2), scrollAxis: Axis.horizontal, ) : Container( alignment: Alignment.centerLeft, child: Text( title, style: AppStyle.textStyleWhite, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ), ), Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ AppStyle.hGap20, Icon( Icons.account_circle, color: focusNode.isFoucsed.value ? Colors.black54 : Colors.white54, size: 32.w, ), AppStyle.hGap12, Expanded( child: Text( anchor, style: focusNode.isFoucsed.value ? AppStyle.subTextStyleBlack : AppStyle.subTextStyleWhite, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), ], ), AppStyle.vGap12, ], ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/highlight_widget.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; typedef FocusOnKeyDownCallback = KeyEventResult Function(); /// 高亮组件 class HighlightWidget extends StatelessWidget { final AppFocusNode focusNode; final Widget child; final FocusOnKeyDownCallback? onUpKey; final FocusOnKeyDownCallback? onDownKey; final FocusOnKeyDownCallback? onLeftKey; final FocusOnKeyDownCallback? onRightKey; final Function(bool)? onFocusChange; final Function()? onTap; final Color foucsedColor; final Color color; final bool autofocus; final BorderRadius? borderRadius; final double order; final bool selected; const HighlightWidget({ required this.focusNode, required this.child, this.onUpKey, this.onDownKey, this.onLeftKey, this.onRightKey, this.onFocusChange, this.onTap, this.autofocus = false, this.selected = false, this.borderRadius, this.order = 0.0, this.color = Colors.transparent, this.foucsedColor = Colors.white, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return FocusTraversalOrder( order: NumericFocusOrder(order), child: Focus( focusNode: focusNode, autofocus: autofocus, onFocusChange: onFocusChange, onKeyEvent: (node, e) { if (e is KeyDownEvent) { if (e.logicalKey == LogicalKeyboardKey.arrowRight) { return onRightKey?.call() ?? KeyEventResult.ignored; } if (e.logicalKey == LogicalKeyboardKey.arrowLeft) { return onLeftKey?.call() ?? KeyEventResult.ignored; } if (e.logicalKey == LogicalKeyboardKey.arrowUp) { return onUpKey?.call() ?? KeyEventResult.ignored; } if (e.logicalKey == LogicalKeyboardKey.arrowDown) { return onDownKey?.call() ?? KeyEventResult.ignored; } if (e.logicalKey == LogicalKeyboardKey.enter || e.logicalKey == LogicalKeyboardKey.select || e.logicalKey == LogicalKeyboardKey.space) { return onTap?.call() ?? KeyEventResult.ignored; } } return KeyEventResult.ignored; }, child: GestureDetector( onTap: onTap, child: Obx( () => AnimatedScale( scale: focusNode.isFoucsed.value ? 1.1 : 1, duration: const Duration(milliseconds: 200), child: GestureDetector( onTap: onTap, child: Container( decoration: BoxDecoration( borderRadius: borderRadius, boxShadow: focusNode.isFoucsed.value ? AppStyle.highlightShadow : null, color: (focusNode.isFoucsed.value || selected) ? foucsedColor : color, ), child: child, ), ), ), ), ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/keep_alive_wrapper.dart ================================================ import 'package:flutter/material.dart'; class KeepAliveWrapper extends StatefulWidget { final Widget child; const KeepAliveWrapper({Key? key, required this.child}) : super(key: key); @override State createState() => _KeepAliveWrapperState(); } class _KeepAliveWrapperState extends State with AutomaticKeepAliveClientMixin { @override Widget build(BuildContext context) { super.build(context); return widget.child; } @override bool get wantKeepAlive => true; } ================================================ FILE: simple_live_tv_app/lib/widgets/net_image.dart ================================================ import 'package:extended_image/extended_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; class NetImage extends StatelessWidget { final String picUrl; final double? width; final double? height; final BoxFit? fit; final double borderRadius; final int? cacheWidth; const NetImage(this.picUrl, {this.width, this.height, this.fit = BoxFit.cover, this.borderRadius = 0, this.cacheWidth, Key? key}) : super(key: key); @override Widget build(BuildContext context) { var pic = picUrl; if (pic.startsWith("//")) { pic = 'https:$pic'; } return ClipRRect( borderRadius: BorderRadius.circular(borderRadius), child: ExtendedImage.network( pic, fit: fit, height: height, width: width, cacheWidth: cacheWidth, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(borderRadius), loadStateChanged: (e) { if (e.extendedImageLoadState == LoadState.loading) { return const SizedBox(); } if (e.extendedImageLoadState == LoadState.failed) { return Icon( Icons.broken_image, color: Colors.grey, size: 24.w, ); } return null; }, ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/page_grid_view.dart ================================================ import 'package:flutter/material.dart'; import 'package:simple_live_tv_app/app/controller/base_controller.dart'; import 'package:simple_live_tv_app/widgets/status/app_empty_widget.dart'; import 'package:simple_live_tv_app/widgets/status/app_error_widget.dart'; import 'package:simple_live_tv_app/widgets/status/app_loadding_widget.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:get/get.dart'; class PageGridView extends StatelessWidget { final BasePageController pageController; final IndexedWidgetBuilder itemBuilder; final EdgeInsets? padding; final bool firstRefresh; final Function()? onLoginSuccess; final bool showPageLoadding; final double crossAxisSpacing, mainAxisSpacing; final int crossAxisCount; const PageGridView({ required this.itemBuilder, required this.pageController, this.padding, this.firstRefresh = false, this.showPageLoadding = false, this.onLoginSuccess, this.crossAxisSpacing = 0.0, this.mainAxisSpacing = 0.0, required this.crossAxisCount, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Obx( () => Stack( children: [ MasonryGridView.count( padding: padding, controller: pageController.scrollController, itemCount: pageController.list.length, itemBuilder: itemBuilder, crossAxisCount: crossAxisCount, crossAxisSpacing: crossAxisSpacing, mainAxisSpacing: mainAxisSpacing, ), Offstage( offstage: !pageController.pageEmpty.value, child: AppEmptyWidget( onRefresh: () => pageController.refreshData(), ), ), Offstage( offstage: !(showPageLoadding && pageController.pageLoadding.value), child: const AppLoaddingWidget(), ), Offstage( offstage: !pageController.pageError.value, child: AppErrorWidget( errorMsg: pageController.errorMsg.value, onRefresh: () => pageController.refreshData(), ), ), ], ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/rectangular_indicator.dart ================================================ import 'package:flutter/material.dart'; /// 来自 https://github.com/adar2378/tab_indicator_styler class RectangularIndicator extends Decoration { /// topRight radius of the indicator, default to 5. final double topRightRadius; /// topLeft radius of the indicator, default to 5. final double topLeftRadius; /// bottomRight radius of the indicator, default to 0. final double bottomRightRadius; /// bottomLeft radius of the indicator, default to 0 final double bottomLeftRadius; /// Color of the indicator, default set to [Colors.black] final Color color; /// Horizontal padding of the indicator, default set to 0 final double horizontalPadding; /// Vertical padding of the indicator, default set to 0 final double verticalPadding; /// [PagingStyle] determines if the indicator should be fill or stroke, default to fill final PaintingStyle paintingStyle; /// StrokeWidth, used for [PaintingStyle.stroke], default set to 0 final double strokeWidth; const RectangularIndicator({ this.topRightRadius = 5, this.topLeftRadius = 5, this.bottomRightRadius = 0, this.bottomLeftRadius = 0, this.color = Colors.black, this.horizontalPadding = 0, this.verticalPadding = 0, this.paintingStyle = PaintingStyle.fill, this.strokeWidth = 2, }); @override MyCustomPainter createBoxPainter([VoidCallback? onChanged]) { return MyCustomPainter( this, onChanged, bottomLeftRadius: bottomLeftRadius, bottomRightRadius: bottomRightRadius, color: color, horizontalPadding: horizontalPadding, topLeftRadius: topLeftRadius, topRightRadius: topRightRadius, verticalPadding: verticalPadding, paintingStyle: paintingStyle, strokeWidth: strokeWidth, ); } } class MyCustomPainter extends BoxPainter { final RectangularIndicator decoration; final double topRightRadius; final double topLeftRadius; final double bottomRightRadius; final double bottomLeftRadius; final Color color; final double horizontalPadding; final double verticalPadding; final PaintingStyle paintingStyle; final double strokeWidth; MyCustomPainter( this.decoration, VoidCallback? onChanged, { required this.topRightRadius, required this.topLeftRadius, required this.bottomRightRadius, required this.bottomLeftRadius, required this.color, required this.horizontalPadding, required this.verticalPadding, required this.paintingStyle, required this.strokeWidth, }) : super(onChanged); @override void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) { assert(horizontalPadding >= 0); assert(horizontalPadding < configuration.size!.width / 2, "Padding must be less than half of the size of the tab"); assert(verticalPadding < configuration.size!.height / 2 && verticalPadding >= 0); assert(strokeWidth >= 0 && strokeWidth < configuration.size!.width / 2 && strokeWidth < configuration.size!.height / 2); //offset is the position from where the decoration should be drawn. //configuration.size tells us about the height and width of the tab. Size mysize = Size(configuration.size!.width - (horizontalPadding * 2), configuration.size!.height - (2 * verticalPadding)); Offset myoffset = Offset(offset.dx + (horizontalPadding), offset.dy + verticalPadding); final Rect rect = myoffset & mysize; final Paint paint = Paint(); paint.color = color; paint.style = paintingStyle; paint.strokeWidth = 3; canvas.drawRRect( RRect.fromRectAndCorners( rect, bottomRight: Radius.circular(bottomRightRadius), bottomLeft: Radius.circular(bottomLeftRadius), topLeft: Radius.circular(topLeftRadius), topRight: Radius.circular(topRightRadius), ), paint); } } ================================================ FILE: simple_live_tv_app/lib/widgets/settings_item_widget.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:simple_live_tv_app/widgets/highlight_widget.dart'; class SettingsItemWidget extends StatelessWidget { final AppFocusNode foucsNode; final Map items; final dynamic value; final String title; final bool autofocus; final Function(dynamic) onChanged; const SettingsItemWidget({ required this.foucsNode, required this.items, required this.value, required this.title, required this.onChanged, this.autofocus = false, super.key, }); @override Widget build(BuildContext context) { return HighlightWidget( focusNode: foucsNode, autofocus: autofocus, borderRadius: AppStyle.radius16, onLeftKey: () { if (items.isEmpty) return KeyEventResult.handled; if (items.keys.first == value) { onChanged(items.keys.last); } else { onChanged( items.keys.elementAt(items.keys.toList().indexOf(value) - 1)); } return KeyEventResult.handled; }, onRightKey: () { if (items.isEmpty) return KeyEventResult.handled; if (items.keys.last == value) { onChanged(items.keys.first); } else { onChanged( items.keys.elementAt(items.keys.toList().indexOf(value) + 1)); } return KeyEventResult.handled; }, onTap: () { showSettingsDialog(); }, child: Obx( () => Padding( padding: AppStyle.edgeInsetsA24, child: Row( children: [ Text( title, style: foucsNode.isFoucsed.value ? AppStyle.textStyleBlack : AppStyle.textStyleWhite, ), const Spacer(), if (foucsNode.isFoucsed.value && items.isNotEmpty) Icon( Icons.chevron_left, size: 40.w, color: foucsNode.isFoucsed.value ? Colors.black : Colors.white, ), AppStyle.hGap12, ConstrainedBox( constraints: BoxConstraints(minWidth: 120.w), child: Text( items[value] ?? '', style: foucsNode.isFoucsed.value ? AppStyle.textStyleBlack : AppStyle.textStyleWhite, textAlign: foucsNode.isFoucsed.value ? TextAlign.center : TextAlign.right, ), ), AppStyle.hGap12, if (foucsNode.isFoucsed.value && items.isNotEmpty) Icon( Icons.chevron_right, size: 40.w, color: foucsNode.isFoucsed.value ? Colors.black : Colors.white, ), ], ), ), ), ); } void showSettingsDialog() { Get.dialog( AlertDialog( backgroundColor: Get.theme.cardColor, surfaceTintColor: Colors.transparent, title: Text(title, style: AppStyle.titleStyleWhite), scrollable: true, content: Column( mainAxisSize: MainAxisSize.min, children: items.keys.map((e) { return ListTile( title: Text(items[e] ?? '', style: AppStyle.textStyleWhite), contentPadding: AppStyle.edgeInsetsH20, autofocus: e == value, shape: RoundedRectangleBorder( borderRadius: AppStyle.radius16, ), focusColor: Colors.white54, onTap: () { onChanged(e); Get.back(); }, ); }).toList(), ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/status/app_empty_widget.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:simple_live_tv_app/app/app_focus_node.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:lottie/lottie.dart'; import 'package:simple_live_tv_app/widgets/button/highlight_button.dart'; class AppEmptyWidget extends StatelessWidget { final Function()? onRefresh; final String? text; const AppEmptyWidget({ this.onRefresh, this.text, Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return Center( child: GestureDetector( onTap: () { onRefresh?.call(); }, child: Padding( padding: AppStyle.edgeInsetsA48, child: Column( mainAxisSize: MainAxisSize.min, children: [ LottieBuilder.asset( 'assets/lotties/empty.json', width: 160.w, height: 160.w, repeat: false, ), AppStyle.vGap24, Text( text ?? "这里什么都没有", textAlign: TextAlign.center, style: AppStyle.textStyleWhite, ), AppStyle.vGap24, if (onRefresh != null) HighlightButton( text: "刷新", iconData: Icons.refresh, onTap: onRefresh, focusNode: AppFocusNode(), ), ], ), ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/status/app_error_widget.dart ================================================ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; import 'package:lottie/lottie.dart'; class AppErrorWidget extends StatelessWidget { final Function()? onRefresh; final String errorMsg; const AppErrorWidget({this.errorMsg = "", this.onRefresh, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: Padding( padding: AppStyle.edgeInsetsA12, child: Column( mainAxisSize: MainAxisSize.min, children: [ LottieBuilder.asset( 'assets/lotties/error.json', width: 200.w, repeat: false, ), AppStyle.vGap24, Text( errorMsg.isEmpty ? "出错了,请稍后重试" : errorMsg, textAlign: TextAlign.center, style: AppStyle.textStyleWhite, ), ], ), ), ); } } ================================================ FILE: simple_live_tv_app/lib/widgets/status/app_loadding_widget.dart ================================================ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:simple_live_tv_app/app/app_style.dart'; class AppLoaddingWidget extends StatelessWidget { const AppLoaddingWidget({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: Container( padding: AppStyle.edgeInsetsA12, decoration: BoxDecoration( shape: BoxShape.circle, color: Theme.of(context).cardColor, boxShadow: Get.isDarkMode ? [] : [ BoxShadow( blurRadius: 4, color: Colors.grey.withAlpha(50), ) ], ), child: const CupertinoActivityIndicator( radius: 10, ), ), ); } } ================================================ FILE: simple_live_tv_app/pubspec.yaml ================================================ name: simple_live_tv_app description: A new Flutter project. publish_to: "none" version: 1.6.5+10605 environment: sdk: ">=3.1.2 <4.0.0" dependencies: flutter: sdk: flutter simple_live_core: path: ../simple_live_core cupertino_icons: ^1.0.2 remixicon: ^1.0.0 #Remix图标 # 框架、工具 get: ^4.7.2 #状态管理、路由管理、国际化 dio: ^5.9.0 #网络请求 hive: 2.2.3 #持久化存储 hive_flutter: 1.1.0 #持久化存储 logger: ^2.6.1 #日志 intl: ^0.20.2 #国际化 flutter_screenutil: ^5.9.3 #UI适配 uuid: ^4.5.1 #UUID signalr_netcore: ^1.4.4 #SignalR crypto: ^3.0.6 #Widget flutter_staggered_grid_view: ^0.7.0 #瀑布流/GridView flutter_easyrefresh: 2.2.2 #下拉刷新、上拉加载 extended_image: ^10.0.1 #拓展Image,支持缓存 flutter_smart_dialog: ^4.9.8+9 #各种弹窗 Toast/Dialog/Popup marquee: ^2.3.0 #跑马灯 lottie: ^3.3.2 #Lottie动画 qr_flutter: ^4.1.0 #二维码 sticky_headers: ^0.3.0+2 #吸顶 canvas_danmaku: ^0.2.7 #弹幕 #系统交互 package_info_plus: ^9.0.0 #包信息 url_launcher: ^6.3.2 #打开链接 network_info_plus: ^7.0.0 shelf: ^1.4.2 shelf_router: ^1.1.4 udp: ^5.0.3 #UDP device_info_plus: ^12.1.0 #设备信息 wakelock_plus: ^1.4.0 #屏幕常亮,media_kit中自带,但似乎不生效 # 视频播放 media_kit: ^1.2.1 media_kit_video: ^1.3.1 media_kit_libs_video: ^1.0.7 dependency_overrides: fading_edge_scrollview: ^4.1.1 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 flutter: uses-material-design: true assets: - assets/statement.txt - assets/images/ - assets/icons/ - assets/lotties/ ================================================ FILE: simple_live_tv_app/test/widget_test.dart ================================================ // This is a basic Flutter widget test. // // To perform an interaction with a widget in your test, use the WidgetTester // utility in the flutter_test package. For example, you can send tap and scroll // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:simple_live_tv_app/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. await tester.pumpWidget(const MyApp()); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget); expect(find.text('1'), findsNothing); // Tap the '+' icon and trigger a frame. await tester.tap(find.byIcon(Icons.add)); await tester.pump(); // Verify that our counter has incremented. expect(find.text('0'), findsNothing); expect(find.text('1'), findsOneWidget); }); } ================================================ FILE: simple_live_tv_app/windows/.gitignore ================================================ flutter/ephemeral/ # Visual Studio user-specific files. *.suo *.user *.userosscache *.sln.docstates # Visual Studio build-related files. x64/ x86/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ ================================================ FILE: simple_live_tv_app/windows/CMakeLists.txt ================================================ # Project-level configuration. cmake_minimum_required(VERSION 3.14) project(simple_live_tv_app LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. set(BINARY_NAME "simple_live_tv_app") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. cmake_policy(VERSION 3.14...3.25) # Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" CACHE STRING "" FORCE) else() if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Flutter build mode" FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Profile" "Release") endif() endif() # Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") # Use Unicode for all projects. add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. # # Be cautious about adding new options here, as plugins use this function by # default. In most cases, you should add new options to specific targets instead # of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") target_compile_options(${TARGET} PRIVATE /EHsc) target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() # Flutter library and tool build rules. set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) # Application build; see runner/CMakeLists.txt. add_subdirectory("runner") # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) # === Installation === # Support files are copied into place next to the executable, so that it can # run in place. This is done instead of making a separate bundle (as on Linux) # so that building and running from within Visual Studio will work. set(BUILD_BUNDLE_DIR "$") # Make the "install" step default, as it's required to run. set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) endif() set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT Runtime) install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) if(PLUGIN_BUNDLED_LIBRARIES) install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime) endif() # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") install(CODE " file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") " COMPONENT Runtime) install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) # Install the AOT library on non-Debug builds only. install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" CONFIGURATIONS Profile;Release COMPONENT Runtime) ================================================ FILE: simple_live_tv_app/windows/flutter/CMakeLists.txt ================================================ # This file controls Flutter-level build steps. It should not be edited. cmake_minimum_required(VERSION 3.14) set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") # Configuration provided via flutter tool. include(${EPHEMERAL_DIR}/generated_config.cmake) # TODO: Move the rest of this into files in ephemeral. See # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") # Set fallback configurations for older versions of the flutter tool. if (NOT DEFINED FLUTTER_TARGET_PLATFORM) set(FLUTTER_TARGET_PLATFORM "windows-x64") endif() # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") # Published to parent scope for install step. set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) list(APPEND FLUTTER_LIBRARY_HEADERS "flutter_export.h" "flutter_windows.h" "flutter_messenger.h" "flutter_plugin_registrar.h" "flutter_texture_registrar.h" ) list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") add_library(flutter INTERFACE) target_include_directories(flutter INTERFACE "${EPHEMERAL_DIR}" ) target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") add_dependencies(flutter flutter_assemble) # === Wrapper === list(APPEND CPP_WRAPPER_SOURCES_CORE "core_implementations.cc" "standard_codec.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_PLUGIN "plugin_registrar.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") list(APPEND CPP_WRAPPER_SOURCES_APP "flutter_engine.cc" "flutter_view_controller.cc" ) list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") # Wrapper sources needed for a plugin. add_library(flutter_wrapper_plugin STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ) apply_standard_settings(flutter_wrapper_plugin) set_target_properties(flutter_wrapper_plugin PROPERTIES POSITION_INDEPENDENT_CODE ON) set_target_properties(flutter_wrapper_plugin PROPERTIES CXX_VISIBILITY_PRESET hidden) target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) target_include_directories(flutter_wrapper_plugin PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_plugin flutter_assemble) # Wrapper sources needed for the runner. add_library(flutter_wrapper_app STATIC ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_APP} ) apply_standard_settings(flutter_wrapper_app) target_link_libraries(flutter_wrapper_app PUBLIC flutter) target_include_directories(flutter_wrapper_app PUBLIC "${WRAPPER_ROOT}/include" ) add_dependencies(flutter_wrapper_app flutter_assemble) # === Flutter tool backend === # _phony_ is a non-existent file to force this command to run every time, # since currently there's no way to get a full input/output list from the # flutter tool. set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) add_custom_command( OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ${PHONY_OUTPUT} COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS "${FLUTTER_LIBRARY}" ${FLUTTER_LIBRARY_HEADERS} ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} ${CPP_WRAPPER_SOURCES_APP} ) ================================================ FILE: simple_live_tv_app/windows/flutter/generated_plugin_registrant.cc ================================================ // // Generated file. Do not edit. // // clang-format off #include "generated_plugin_registrant.h" #include #include #include #include void RegisterPlugins(flutter::PluginRegistry* registry) { MediaKitLibsWindowsVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitLibsWindowsVideoPluginCApi")); MediaKitVideoPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("MediaKitVideoPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); VolumeControllerPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("VolumeControllerPluginCApi")); } ================================================ FILE: simple_live_tv_app/windows/flutter/generated_plugin_registrant.h ================================================ // // Generated file. Do not edit. // // clang-format off #ifndef GENERATED_PLUGIN_REGISTRANT_ #define GENERATED_PLUGIN_REGISTRANT_ #include // Registers Flutter plugins. void RegisterPlugins(flutter::PluginRegistry* registry); #endif // GENERATED_PLUGIN_REGISTRANT_ ================================================ FILE: simple_live_tv_app/windows/flutter/generated_plugins.cmake ================================================ # # Generated file, do not edit. # list(APPEND FLUTTER_PLUGIN_LIST media_kit_libs_windows_video media_kit_video url_launcher_windows volume_controller ) list(APPEND FLUTTER_FFI_PLUGIN_LIST ) set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) endforeach(ffi_plugin) ================================================ FILE: simple_live_tv_app/windows/runner/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the build version. target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) ================================================ FILE: simple_live_tv_app/windows/runner/Runner.rc ================================================ // Microsoft Visual C++ generated resource script. // #pragma code_page(65001) #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (United States) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_APP_ICON ICON "resources\\app_icon.ico" ///////////////////////////////////////////////////////////////////////////// // // Version // #if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) #define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else #define VERSION_AS_NUMBER 1,0,0,0 #endif #if defined(FLUTTER_VERSION) #define VERSION_AS_STRING FLUTTER_VERSION #else #define VERSION_AS_STRING "1.0.0" #endif VS_VERSION_INFO VERSIONINFO FILEVERSION VERSION_AS_NUMBER PRODUCTVERSION VERSION_AS_NUMBER FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 FILETYPE VFT_APP FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "com.example" "\0" VALUE "FileDescription", "simple_live_tv_app" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "simple_live_tv_app" "\0" VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0" VALUE "OriginalFilename", "simple_live_tv_app.exe" "\0" VALUE "ProductName", "simple_live_tv_app" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED ================================================ FILE: simple_live_tv_app/windows/runner/flutter_window.cpp ================================================ #include "flutter_window.h" #include #include "flutter/generated_plugin_registrant.h" FlutterWindow::FlutterWindow(const flutter::DartProject& project) : project_(project) {} FlutterWindow::~FlutterWindow() {} bool FlutterWindow::OnCreate() { if (!Win32Window::OnCreate()) { return false; } RECT frame = GetClientArea(); // The size here must match the window dimensions to avoid unnecessary surface // creation / destruction in the startup path. flutter_controller_ = std::make_unique( frame.right - frame.left, frame.bottom - frame.top, project_); // Ensure that basic setup of the controller was successful. if (!flutter_controller_->engine() || !flutter_controller_->view()) { return false; } RegisterPlugins(flutter_controller_->engine()); SetChildContent(flutter_controller_->view()->GetNativeWindow()); flutter_controller_->engine()->SetNextFrameCallback([&]() { this->Show(); }); // Flutter can complete the first frame before the "show window" callback is // registered. The following call ensures a frame is pending to ensure the // window is shown. It is a no-op if the first frame hasn't completed yet. flutter_controller_->ForceRedraw(); return true; } void FlutterWindow::OnDestroy() { if (flutter_controller_) { flutter_controller_ = nullptr; } Win32Window::OnDestroy(); } LRESULT FlutterWindow::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { // Give Flutter, including plugins, an opportunity to handle window messages. if (flutter_controller_) { std::optional result = flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, lparam); if (result) { return *result; } } switch (message) { case WM_FONTCHANGE: flutter_controller_->engine()->ReloadSystemFonts(); break; } return Win32Window::MessageHandler(hwnd, message, wparam, lparam); } ================================================ FILE: simple_live_tv_app/windows/runner/flutter_window.h ================================================ #ifndef RUNNER_FLUTTER_WINDOW_H_ #define RUNNER_FLUTTER_WINDOW_H_ #include #include #include #include "win32_window.h" // A window that does nothing but host a Flutter view. class FlutterWindow : public Win32Window { public: // Creates a new FlutterWindow hosting a Flutter view running |project|. explicit FlutterWindow(const flutter::DartProject& project); virtual ~FlutterWindow(); protected: // Win32Window: bool OnCreate() override; void OnDestroy() override; LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept override; private: // The project to run. flutter::DartProject project_; // The Flutter instance hosted by this window. std::unique_ptr flutter_controller_; }; #endif // RUNNER_FLUTTER_WINDOW_H_ ================================================ FILE: simple_live_tv_app/windows/runner/main.cpp ================================================ #include #include #include #include "flutter_window.h" #include "utils.h" int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { CreateAndAttachConsole(); } // Initialize COM, so that it is available for use in the library and/or // plugins. ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); flutter::DartProject project(L"data"); std::vector command_line_arguments = GetCommandLineArguments(); project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); if (!window.Create(L"simple_live_tv_app", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); ::MSG msg; while (::GetMessage(&msg, nullptr, 0, 0)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } ::CoUninitialize(); return EXIT_SUCCESS; } ================================================ FILE: simple_live_tv_app/windows/runner/resource.h ================================================ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by Runner.rc // #define IDI_APP_ICON 101 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif ================================================ FILE: simple_live_tv_app/windows/runner/runner.exe.manifest ================================================ PerMonitorV2 ================================================ FILE: simple_live_tv_app/windows/runner/utils.cpp ================================================ #include "utils.h" #include #include #include #include #include void CreateAndAttachConsole() { if (::AllocConsole()) { FILE *unused; if (freopen_s(&unused, "CONOUT$", "w", stdout)) { _dup2(_fileno(stdout), 1); } if (freopen_s(&unused, "CONOUT$", "w", stderr)) { _dup2(_fileno(stdout), 2); } std::ios::sync_with_stdio(); FlutterDesktopResyncOutputStreams(); } } std::vector GetCommandLineArguments() { // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. int argc; wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); if (argv == nullptr) { return std::vector(); } std::vector command_line_arguments; // Skip the first argument as it's the binary name. for (int i = 1; i < argc; i++) { command_line_arguments.push_back(Utf8FromUtf16(argv[i])); } ::LocalFree(argv); return command_line_arguments; } std::string Utf8FromUtf16(const wchar_t* utf16_string) { if (utf16_string == nullptr) { return std::string(); } int target_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, -1, nullptr, 0, nullptr, nullptr) -1; // remove the trailing null character int input_length = (int)wcslen(utf16_string); std::string utf8_string; if (target_length <= 0 || target_length > utf8_string.max_size()) { return utf8_string; } utf8_string.resize(target_length); int converted_length = ::WideCharToMultiByte( CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, input_length, utf8_string.data(), target_length, nullptr, nullptr); if (converted_length == 0) { return std::string(); } return utf8_string; } ================================================ FILE: simple_live_tv_app/windows/runner/utils.h ================================================ #ifndef RUNNER_UTILS_H_ #define RUNNER_UTILS_H_ #include #include // Creates a console for the process, and redirects stdout and stderr to // it for both the runner and the Flutter library. void CreateAndAttachConsole(); // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string // encoded in UTF-8. Returns an empty std::string on failure. std::string Utf8FromUtf16(const wchar_t* utf16_string); // Gets the command line arguments passed in as a std::vector, // encoded in UTF-8. Returns an empty std::vector on failure. std::vector GetCommandLineArguments(); #endif // RUNNER_UTILS_H_ ================================================ FILE: simple_live_tv_app/windows/runner/win32_window.cpp ================================================ #include "win32_window.h" #include #include #include "resource.h" namespace { /// Window attribute that enables dark mode window decorations. /// /// Redefined in case the developer's machine has a Windows SDK older than /// version 10.0.22000.0. /// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute #ifndef DWMWA_USE_IMMERSIVE_DARK_MODE #define DWMWA_USE_IMMERSIVE_DARK_MODE 20 #endif constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; /// Registry key for app theme preference. /// /// A value of 0 indicates apps should use dark mode. A non-zero or missing /// value indicates apps should use light mode. constexpr const wchar_t kGetPreferredBrightnessRegKey[] = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; // The number of Win32Window objects that currently exist. static int g_active_window_count = 0; using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); // Scale helper to convert logical scaler values to physical using passed in // scale factor int Scale(int source, double scale_factor) { return static_cast(source * scale_factor); } // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. // This API is only needed for PerMonitor V1 awareness mode. void EnableFullDpiSupportIfAvailable(HWND hwnd) { HMODULE user32_module = LoadLibraryA("User32.dll"); if (!user32_module) { return; } auto enable_non_client_dpi_scaling = reinterpret_cast( GetProcAddress(user32_module, "EnableNonClientDpiScaling")); if (enable_non_client_dpi_scaling != nullptr) { enable_non_client_dpi_scaling(hwnd); } FreeLibrary(user32_module); } } // namespace // Manages the Win32Window's window class registration. class WindowClassRegistrar { public: ~WindowClassRegistrar() = default; // Returns the singleton registrar instance. static WindowClassRegistrar* GetInstance() { if (!instance_) { instance_ = new WindowClassRegistrar(); } return instance_; } // Returns the name of the window class, registering the class if it hasn't // previously been registered. const wchar_t* GetWindowClass(); // Unregisters the window class. Should only be called if there are no // instances of the window. void UnregisterWindowClass(); private: WindowClassRegistrar() = default; static WindowClassRegistrar* instance_; bool class_registered_ = false; }; WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; const wchar_t* WindowClassRegistrar::GetWindowClass() { if (!class_registered_) { WNDCLASS window_class{}; window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); window_class.lpszClassName = kWindowClassName; window_class.style = CS_HREDRAW | CS_VREDRAW; window_class.cbClsExtra = 0; window_class.cbWndExtra = 0; window_class.hInstance = GetModuleHandle(nullptr); window_class.hIcon = LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); window_class.hbrBackground = 0; window_class.lpszMenuName = nullptr; window_class.lpfnWndProc = Win32Window::WndProc; RegisterClass(&window_class); class_registered_ = true; } return kWindowClassName; } void WindowClassRegistrar::UnregisterWindowClass() { UnregisterClass(kWindowClassName, nullptr); class_registered_ = false; } Win32Window::Win32Window() { ++g_active_window_count; } Win32Window::~Win32Window() { --g_active_window_count; Destroy(); } bool Win32Window::Create(const std::wstring& title, const Point& origin, const Size& size) { Destroy(); const wchar_t* window_class = WindowClassRegistrar::GetInstance()->GetWindowClass(); const POINT target_point = {static_cast(origin.x), static_cast(origin.y)}; HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); double scale_factor = dpi / 96.0; HWND window = CreateWindow( window_class, title.c_str(), WS_OVERLAPPEDWINDOW, Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), Scale(size.width, scale_factor), Scale(size.height, scale_factor), nullptr, nullptr, GetModuleHandle(nullptr), this); if (!window) { return false; } UpdateTheme(window); return OnCreate(); } bool Win32Window::Show() { return ShowWindow(window_handle_, SW_SHOWNORMAL); } // static LRESULT CALLBACK Win32Window::WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { if (message == WM_NCCREATE) { auto window_struct = reinterpret_cast(lparam); SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast(window_struct->lpCreateParams)); auto that = static_cast(window_struct->lpCreateParams); EnableFullDpiSupportIfAvailable(window); that->window_handle_ = window; } else if (Win32Window* that = GetThisFromHandle(window)) { return that->MessageHandler(window, message, wparam, lparam); } return DefWindowProc(window, message, wparam, lparam); } LRESULT Win32Window::MessageHandler(HWND hwnd, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept { switch (message) { case WM_DESTROY: window_handle_ = nullptr; Destroy(); if (quit_on_close_) { PostQuitMessage(0); } return 0; case WM_DPICHANGED: { auto newRectSize = reinterpret_cast(lparam); LONG newWidth = newRectSize->right - newRectSize->left; LONG newHeight = newRectSize->bottom - newRectSize->top; SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } case WM_SIZE: { RECT rect = GetClientArea(); if (child_content_ != nullptr) { // Size and position the child window. MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, TRUE); } return 0; } case WM_ACTIVATE: if (child_content_ != nullptr) { SetFocus(child_content_); } return 0; case WM_DWMCOLORIZATIONCOLORCHANGED: UpdateTheme(hwnd); return 0; } return DefWindowProc(window_handle_, message, wparam, lparam); } void Win32Window::Destroy() { OnDestroy(); if (window_handle_) { DestroyWindow(window_handle_); window_handle_ = nullptr; } if (g_active_window_count == 0) { WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); } } Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { return reinterpret_cast( GetWindowLongPtr(window, GWLP_USERDATA)); } void Win32Window::SetChildContent(HWND content) { child_content_ = content; SetParent(content, window_handle_); RECT frame = GetClientArea(); MoveWindow(content, frame.left, frame.top, frame.right - frame.left, frame.bottom - frame.top, true); SetFocus(child_content_); } RECT Win32Window::GetClientArea() { RECT frame; GetClientRect(window_handle_, &frame); return frame; } HWND Win32Window::GetHandle() { return window_handle_; } void Win32Window::SetQuitOnClose(bool quit_on_close) { quit_on_close_ = quit_on_close; } bool Win32Window::OnCreate() { // No-op; provided for subclasses. return true; } void Win32Window::OnDestroy() { // No-op; provided for subclasses. } void Win32Window::UpdateTheme(HWND const window) { DWORD light_mode; DWORD light_mode_size = sizeof(light_mode); LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, kGetPreferredBrightnessRegValue, RRF_RT_REG_DWORD, nullptr, &light_mode, &light_mode_size); if (result == ERROR_SUCCESS) { BOOL enable_dark_mode = light_mode == 0; DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, &enable_dark_mode, sizeof(enable_dark_mode)); } } ================================================ FILE: simple_live_tv_app/windows/runner/win32_window.h ================================================ #ifndef RUNNER_WIN32_WINDOW_H_ #define RUNNER_WIN32_WINDOW_H_ #include #include #include #include // A class abstraction for a high DPI-aware Win32 Window. Intended to be // inherited from by classes that wish to specialize with custom // rendering and input handling class Win32Window { public: struct Point { unsigned int x; unsigned int y; Point(unsigned int x, unsigned int y) : x(x), y(y) {} }; struct Size { unsigned int width; unsigned int height; Size(unsigned int width, unsigned int height) : width(width), height(height) {} }; Win32Window(); virtual ~Win32Window(); // Creates a win32 window with |title| that is positioned and sized using // |origin| and |size|. New windows are created on the default monitor. Window // sizes are specified to the OS in physical pixels, hence to ensure a // consistent size this function will scale the inputted width and height as // as appropriate for the default monitor. The window is invisible until // |Show| is called. Returns true if the window was created successfully. bool Create(const std::wstring& title, const Point& origin, const Size& size); // Show the current window. Returns true if the window was successfully shown. bool Show(); // Release OS resources associated with window. void Destroy(); // Inserts |content| into the window tree. void SetChildContent(HWND content); // Returns the backing Window handle to enable clients to set icon and other // window properties. Returns nullptr if the window has been destroyed. HWND GetHandle(); // If true, closing this window will quit the application. void SetQuitOnClose(bool quit_on_close); // Return a RECT representing the bounds of the current client area. RECT GetClientArea(); protected: // Processes and route salient window messages for mouse handling, // size change and DPI. Delegates handling of these to member overloads that // inheriting classes can handle. virtual LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Called when CreateAndShow is called, allowing subclass window-related // setup. Subclasses should return false if setup fails. virtual bool OnCreate(); // Called when Destroy is called. virtual void OnDestroy(); private: friend class WindowClassRegistrar; // OS callback called by message pump. Handles the WM_NCCREATE message which // is passed when the non-client area is being created and enables automatic // non-client DPI scaling so that the non-client area automatically // responds to changes in DPI. All other messages are handled by // MessageHandler. static LRESULT CALLBACK WndProc(HWND const window, UINT const message, WPARAM const wparam, LPARAM const lparam) noexcept; // Retrieves a class instance pointer for |window| static Win32Window* GetThisFromHandle(HWND const window) noexcept; // Update the window frame's theme to match the system theme. static void UpdateTheme(HWND const window); bool quit_on_close_ = false; // window handle for top level window. HWND window_handle_ = nullptr; // window handle for hosted content. HWND child_content_ = nullptr; }; #endif // RUNNER_WIN32_WINDOW_H_