feat: enhance login capabilities with error messages, QR code, and cookie persistence#2
feat: enhance login capabilities with error messages, QR code, and cookie persistence#2Zhenghao-Wen wants to merge 14 commits into2697a:masterfrom
Conversation
music_api.dart
📝 WalkthroughWalkthroughThis pull request refactors JSON serialization across multiple entity files from an export-based pattern to a part-based pattern using Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (7)
pubspec.yaml (1)
9-25:⚠️ Potential issue | 🔴 CriticalAdd
json_annotationtodependencies(not only codegen tooling).Lines 24-25 add codegen tooling, but
lib/directly importsjson_annotationacross 24+ entity files. Without a direct runtime dependency, downstream package consumers will fail dependency resolution.🔧 Proposed fix
dependencies: flutter: sdk: flutter + json_annotation: ^4.10.0 dio: ^5.7.0 dio_cookie_manager: ^3.1.1 cookie_jar: ^4.0.8🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pubspec.yaml` around lines 9 - 25, The pubspec currently lists json_serializable and build_runner under dev_dependencies but the library code imports json_annotation at runtime; update the pubspec so json_annotation is added to the regular dependencies section (not dev_dependencies), e.g. add the package name "json_annotation" with a compatible version alongside other dependencies so downstream consumers can resolve it; ensure you remove it from dev_dependencies if present and run flutter pub get to confirm resolution.lib/api/song/entity/song_detail_entity.dart (1)
54-55:⚠️ Potential issue | 🔴 CriticalSame
@JSONField-is-silently-ignored bug:sIdwill never deserialize from API responses.
@JSONField(name: "s_id")is not recognized byjson_serializable. The generated code readsjson['sId']instead ofjson['s_id'], so this field will always benull.🐛 Proposed fix
- `@JSONField`(name: "s_id") + `@JsonKey`(name: 's_id') int? sId = 0;Regenerate
song_detail_entity.g.dartafter the change.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/song/entity/song_detail_entity.dart` around lines 54 - 55, The sId field uses the `@JSONField`(name: "s_id") annotation which json_serializable ignores, so deserialization looks for json['sId'] and yields null; update the Dart model to use the json_serializable-supported annotation (e.g. `@JsonKey`(name: 's_id')) on the int? sId field in song_detail_entity.dart and then regenerate the generated file (song_detail_entity.g.dart) so the generated fromJson/toJson use 's_id' correctly.lib/api/album/entity/album_info_entity.dart (1)
98-99:⚠️ Potential issue | 🔴 Critical
@JSONFieldis silently ignored byjson_serializable— these fields will always deserialize asnull.
json_serializableonly recognizes@JsonKeyfrompackage:json_annotationto customize field mappings. The custom@JSONFieldannotation fromjson_field.dartis not recognized by the code generator, so it falls back to using the Dart identifier name as the JSON key.This is confirmed in the generated
album_info_entity.g.dart: the code readsjson['picStr']instead ofjson['pic_str'],json['picidStr']instead ofjson['picId_str'], and so on for all five affected fields:
AlbumInfoSongsAl.picStr→ readsjson['picStr']instead ofjson['pic_str'](Line 98)AlbumInfoAlbum.picidStr→ readsjson['picidStr']instead ofjson['picId_str'](Line 307)AlbumInfoAlbumArtists.img1v1idStr→ readsjson['img1v1idStr']instead ofjson['img1v1Id_str'](Line 338)AlbumInfoAlbumArtist.picidStr→ readsjson['picidStr']instead ofjson['picId_str'](Line 368)AlbumInfoAlbumArtist.img1v1idStr→ readsjson['img1v1idStr']instead ofjson['img1v1Id_str'](Line 371)Replace
@JSONField(name: "...")with@JsonKey(name: '...')on all five affected fields and regenerate withdart run build_runner build --delete-conflicting-outputs.Proposed fixes
- `@JSONField`(name: "pic_str") + `@JsonKey`(name: 'pic_str') String? picStr = '';- `@JSONField`(name: "picId_str") + `@JsonKey`(name: 'picId_str') String? picidStr = '';- `@JSONField`(name: "img1v1Id_str") + `@JsonKey`(name: 'img1v1Id_str') String? img1v1idStr = '';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/album/entity/album_info_entity.dart` around lines 98 - 99, The `@JSONField` annotations are ignored by json_serializable so fields deserialize with wrong keys; replace each `@JSONField`(name: "...") with `@JsonKey`(name: '...') on the affected fields—AlbumInfoSongsAl.picStr, AlbumInfoAlbum.picidStr, AlbumInfoAlbumArtists.img1v1idStr, AlbumInfoAlbumArtist.picidStr, and AlbumInfoAlbumArtist.img1v1idStr—and then regenerate the generated code by running dart run build_runner build --delete-conflicting-outputs.lib/api/playlist/entity/create_playlist_entity.dart (1)
65-66:⚠️ Potential issue | 🟠 MajorReplace
@JSONFieldwith@JsonKey— annotation is silently ignored byjson_serializable.The
@JSONField(name: "coverImgId_str")annotation at line 65 belongs to the old custom code generator and is not recognized byjson_serializable, which only processes@JsonKeyfromjson_annotation. The generated code confirms this: the field serializes to'coverimgidStr'(the Dart field name) instead of the intended'coverImgId_str', causing a silent serialization regression.Fix
- `@JSONField`(name: "coverImgId_str") - String? coverimgidStr = ''; + `@JsonKey`(name: 'coverImgId_str') + String? coverimgidStr = '';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/playlist/entity/create_playlist_entity.dart` around lines 65 - 66, The `@JSONField` annotation on the field coverimgidStr is not recognized by json_serializable; replace `@JSONField`(name: "coverImgId_str") with `@JsonKey`(name: "coverImgId_str") and ensure the file imports the json_annotation package (import 'package:json_annotation/json_annotation.dart';) so json_serializable will generate the correct key mapping for the field in CreatePlaylistEntity (and update any other fields using `@JSONField` similarly).lib/api/song/entity/new_song_entity.dart (1)
166-167:⚠️ Potential issue | 🟠 Major
@JSONFieldignored byjson_serializableacross four fields — wrong JSON keys will be generated.All four
@JSONField(name: ...)usages in this file (NewSongDataArtists.img1v1idStr,NewSongDataAlbum.picidStr,NewSongDataAlbumArtists.img1v1idStr,NewSongDataAlbumArtist.img1v1idStr) are silently ignored byjson_serializable, which only processes@JsonKey. The generated code emits the Dart field name as the JSON key (e.g.,img1v1idStrinstead ofimg1v1Id_str), breaking round-trip serialization.🐛 Proposed fix (apply to all four occurrences)
Replace all instances of
@JSONField(name: ...)with@JsonKey(name: ...):Lines 166–167 and 308–309 and 338–339:
- `@JSONField`(name: "img1v1Id_str") + `@JsonKey`(name: 'img1v1Id_str')Lines 278–279:
- `@JSONField`(name: "picId_str") + `@JsonKey`(name: 'picId_str')Also applies to: 278–279, 308–309, 338–339
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/song/entity/new_song_entity.dart` around lines 166 - 167, Replace the incorrect `@JSONField` usages with json_serializable's `@JsonKey` for the four fields so the generated JSON keys match the desired names: update NewSongDataArtists.img1v1idStr, NewSongDataAlbum.picidStr, NewSongDataAlbumArtists.img1v1idStr, and NewSongDataAlbumArtist.img1v1idStr to use `@JsonKey`(name: "img1v1Id_str") or `@JsonKey`(name: "picId_str") as appropriate; ensure the json_annotation import is present so the generator recognizes `@JsonKey` and then re-run code generation.lib/api/user/entity/user_playlist_entity.dart (1)
64-65:⚠️ Potential issue | 🟠 MajorReplace
@JSONFieldwith@JsonKey—json_serializableignores@JSONFieldand generates incorrect JSON key mappings.The
@JSONFieldannotation is not recognized byjson_serializable. Instead, use@JsonKeyfrom thejson_annotationpackage. The generated code currently mapscoverimgidStrandavatarimgidStrto lowercase JSON keys, not the intendedcoverImgId_strandavatarImgId_str.🐛 Proposed fix
- `@JSONField`(name: "coverImgId_str") + `@JsonKey`(name: 'coverImgId_str') String? coverimgidStr = '';- `@JSONField`(name: "avatarImgId_str") + `@JsonKey`(name: 'avatarImgId_str') String? avatarimgidStr = '';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/user/entity/user_playlist_entity.dart` around lines 64 - 65, Replace the unrecognized `@JSONField` annotations with `@JsonKey` from json_annotation for the fields coverimgidStr and avatarimgidStr so json_serializable generates the correct JSON names; specifically, update the annotations on the String? coverimgidStr and String? avatarimgidStr members to `@JsonKey`(name: 'coverImgId_str') and `@JsonKey`(name: 'avatarImgId_str') respectively and ensure json_annotation is imported so the generated code maps to the exact camelCase+suffix keys.lib/api/album/entity/new_album_entity.dart (1)
53-54:⚠️ Potential issue | 🔴 CriticalReplace
@JSONFieldwith@JsonKey— field name mappings are being silently ignored.
@JSONFieldis a custom annotation from the legacy code generator that is no longer being processed. The current code generator (json_serializable) only recognizes@JsonKeyfrom thejson_annotationpackage. The generated code at line 59 ofnew_album_entity.g.dartreadsjson['picidStr']instead ofjson['picId_str'], causing these fields to deserialize asnullwhen the API sends snake_case field names.This affects all 28
@JSONFieldoccurrences across the codebase (innew_album_entity.dart,album_info_entity.dart,new_song_entity.dart, and 8 other entity files).Proposed fix — replace `@JSONField` with `@JsonKey`
- `@JSONField`(name: "picId_str") + `@JsonKey`(name: 'picId_str') String? picidStr = '';Apply the same change to all other
@JSONFieldoccurrences across the codebase (all 28 instances).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/album/entity/new_album_entity.dart` around lines 53 - 54, Replace legacy `@JSONField` annotations with json_serializable's `@JsonKey` and ensure the name mapping matches the snake_case API keys (e.g., change the field annotation on String? picidStr from `@JSONField`(name: "picId_str") to `@JsonKey`(name: "picId_str")); update all other occurrences of `@JSONField` across entity classes (e.g., in new_album_entity.dart, album_info_entity.dart, new_song_entity.dart) and add/import package: json_annotation/json_annotation.dart if missing, then re-run the build_runner code generation to regenerate *.g.dart files so the deserialization reads json['picId_str'] correctly.
♻️ Duplicate comments (1)
lib/api/user/entity/bool_entity.dart (1)
1-4: Same stalejson_field.dartimport as insong_url_entity.dart— no@JSONFieldannotations are present in this file.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/user/entity/bool_entity.dart` around lines 1 - 4, The file contains an unused import of package:bujuan_music_api/generated/json/base/json_field.dart in bool_entity.dart; either remove that import line (since there are no `@JSONField` annotations) or if you intended to use JSONField, add the appropriate `@JSONField` annotations to the relevant class/fields (e.g., the BoolEntity class and its members) and then regenerate the part file; update the import accordingly.
🧹 Nitpick comments (6)
lib/api/song/entity/song_url_entity.dart (1)
1-4: Stale import:json_field.dartis no longer used in this file.No field in
SongUrlEntityor any of its nested classes uses@JSONField. The import can be removed.🧹 Proposed cleanup
import 'package:json_annotation/json_annotation.dart'; -import 'package:bujuan_music_api/generated/json/base/json_field.dart'; import 'dart:convert'; part 'song_url_entity.g.dart';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/song/entity/song_url_entity.dart` around lines 1 - 4, The import 'package:bujuan_music_api/generated/json/base/json_field.dart' is unused in this file; remove that import line from lib/api/song/entity/song_url_entity.dart so only the needed imports remain (retain imports for json_annotation, dart:convert and the part 'song_url_entity.g.dart'); update any analyzer/formatting by running the Dart analyzer/formatter to ensure no remaining references to JSONField or unused-import warnings for the SongUrlEntity related code.lib/api/user/entity/login_entity.g.dart (1)
26-37: Nested objects not explicitly serialized in_$LoginEntityToJson— addexplicitToJson: true.With the default
explicitToJson: false,instance.account,instance.profile, andinstance.bindingsare placed into the map as raw Dart objects, not asMap<String, dynamic>.jsonEncodehandles this recursively, but any caller that consumes the returned map directly (e.g., for building an HTTP request body) will receive un-serialized nested objects.The same issue exists in
_$LoginProfileToJsonat Line 122 (instance.experts).Fix in the source entity file (
login_entity.dart):-@JsonSerializable() +@JsonSerializable(explicitToJson: true) class LoginEntity {After regenerating, the output will become:
-'account': instance.account, +'account': instance.account?.toJson(), -'profile': instance.profile, +'profile': instance.profile?.toJson(), -'bindings': instance.bindings, +'bindings': instance.bindings?.map((e) => e.toJson()).toList(),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/user/entity/login_entity.g.dart` around lines 26 - 37, The generated JSON serializers _$LoginEntityToJson and _$LoginProfileToJson are leaving nested fields (LoginEntity.account, LoginEntity.profile, LoginEntity.bindings and LoginProfile.experts) as raw Dart objects; update the source model annotation in login_entity.dart to enable explicitToJson: true for the JsonSerializable on LoginEntity (and LoginProfile if separate), re-run the code generator to regenerate _$LoginEntityToJson and _$LoginProfileToJson so nested objects are serialized via their toJson() methods instead of being embedded as raw objects.lib/api/user/user_api.dart (2)
7-7: Remove trailing inline comment// 新增.Debug/development comments like this shouldn't be committed. The import itself is self-explanatory.
Proposed fix
-import 'package:bujuan_music_api/api/user/entity/qr_check_result_entity.dart'; // 新增 +import 'package:bujuan_music_api/api/user/entity/qr_check_result_entity.dart';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/user/user_api.dart` at line 7, Remove the trailing inline comment from the import statement that brings in qr_check_result_entity (import 'package:bujuan_music_api/api/user/entity/qr_check_result_entity.dart';) so the import stands alone without the debug/dev comment "// 新增"; simply delete the comment text and keep the import unchanged.
88-115:qrCodeLoginbypasses the library's ownpost<T>abstraction.Every other method in this mixin delegates to
BujuanMusicManager().post<T>(...), which handles response parsing, interceptors, and error flow uniformly. This method callsdio.post(...)directly, introducing a parallel code path with manual JSON parsing (lines 97-102) and ad-hoc cookie extraction.If the motivation is cookie access, consider extending
BujuanMusicManager.post<T>(or adding a variant) that exposes the rawResponseso cookie headers can be extracted without duplicating response-handling logic.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/user/user_api.dart` around lines 88 - 115, The qrCodeLogin method bypasses the shared HTTP abstraction by calling BujuanMusicManager().dio.post directly and doing manual JSON parsing and cookie extraction; change qrCodeLogin to use BujuanMusicManager.post<T>(...) so it benefits from unified parsing/interceptors, or add a new BujuanMusicManager.postRaw(...) (or a flag on post) that returns the raw Response so qrCodeLogin can call that, parse the body into QrCheckResultEntity via the existing JSON parsing path, and extract cookies from response.headers['set-cookie'] to set result.cookie; update qrCodeLogin to remove the manual jsonDecode branch and rely on the manager's parsing behavior.lib/api/user/entity/login_entity.dart (1)
1-5: Unused import from old codegen system.Line 2 imports
json_field.dartwhich provides the@JSONFieldannotation from the previous code generation approach. Now that all classes use@JsonSerializable()(fromjson_annotation),@JSONFieldshould not be used. Once the annotation on Line 79 is replaced with@JsonKey, this import becomes dead code and should be removed.♻️ Proposed fix (after fixing the `@JSONField` → `@JsonKey` issue)
import 'package:json_annotation/json_annotation.dart'; -import 'package:bujuan_music_api/generated/json/base/json_field.dart'; import 'dart:convert';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/user/entity/login_entity.dart` around lines 1 - 5, The file imports an unused legacy annotation package (import 'package:bujuan_music_api/generated/json/base/json_field.dart') and still uses `@JSONField`; update the class to use `@JsonKey` instead of `@JSONField` (replace the annotation on the login entity) and then remove the now-dead import statement; ensure only 'package:json_annotation/json_annotation.dart' remains and regenerate/verify generated files for the changes to login_entity (look for `@JSONField`, `@JsonKey`, and the import at the top to locate the spots to edit).lib/api/song/entity/new_song_entity.g.dart (1)
72-108: Nested objects intoJsonaren't recursively serialized to maps.The
toJsonmethods insert nested object instances directly (e.g.,'privilege': instance.privilege) instead of calling.toJson()on them. This is the defaultjson_serializablebehavior whenexplicitToJson: trueis not set. It works fine withjsonEncode()(which callstoJson()automatically), but if consumers inspect the rawMapwithout encoding, nested values will be object references, not plain maps.Consider adding
@JsonSerializable(explicitToJson: true)to the parent classes innew_song_entity.dartif the rawMaprepresentation needs to be fully serialized.Also applies to: 146-175, 355-381
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/api/song/entity/new_song_entity.g.dart` around lines 72 - 108, The generated toJson (e.g., _$NewSongDataToJson) is embedding nested object instances (fields like privilege, artists, album, hMusic, mMusic, lMusic, bMusic, etc.) instead of their Maps; fix by annotating the corresponding parent classes in new_song_entity.dart (e.g., class NewSongData and any nested entity classes referenced) with `@JsonSerializable`(explicitToJson: true), then re-run the code generator (build_runner) to regenerate the *.g.dart so the generated toJson calls use .toJson() for nested objects; ensure you update all affected classes mentioned in the review so sections at lines ~72-108, 146-175 and 355-381 are regenerated correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@flutter`:
- Line 1: The Flutter submodule was advanced to commit
90673a4eef275d1a6692c26ac80d6d746d41a73a (Flutter 3.41.2) without explanation;
either document the upgrade rationale in the PR and commit message (e.g.,
required API, dependency, or bugfix) and add a minimum SDK constraint in
pubspec.yaml (e.g., environment.sdk / flutter minimum version) to prevent
accidental use on older toolchains, or if the bump was unintentional revert the
flutter submodule to the previous pinned commit and update the PR description to
state that no Flutter version change is intended.
In `@lib/api/album/entity/album_info_entity.g.dart`:
- Around line 133-148: The generated serialization uses Dart field names for
keys (e.g., AlbumInfoSongsAl.picStr, picidStr, img1v1idStr) instead of the API
keys (pic_str, picId_str, img1v1Id_str), causing incorrect fromJson/toJson
behavior; to fix, update the model annotations in album_info_entity.dart by
replacing the incorrect `@JSONField` annotations with the proper
JsonSerializable-compatible `@JsonKey`(name: '...') attributes for the fields
(e.g., use `@JsonKey`(name: 'pic_str') for picStr, `@JsonKey`(name: 'picId_str') for
picidStr, `@JsonKey`(name: 'img1v1Id_str') for img1v1idStr), then re-run the code
generator to regenerate the _$AlbumInfoSongsAlFromJson/_$AlbumInfoSongsAlToJson
and other affected serializers so they read/write the correct JSON keys.
In `@lib/api/playlist/entity/playlist_detail_entity.dart`:
- Around line 1-4: The custom `@JSONField` annotations are not recognized by
json_serializable so the aliased JSON keys aren’t used; replace each
`@JSONField`(name: "...") with `@JsonKey`(name: "...") on the listed fields so the
generated code uses the correct JSON names: change the annotation on
coverImgId_str in class PlaylistDetailPlaylist, avatarImgId_str in
PlaylistDetailPlaylistSubscribers, avatarImgId_str in
PlaylistDetailPlaylistCreator, s_id in PlaylistDetailPlaylistTracks, and pic_str
in PlaylistDetailPlaylistTracksAl to use `@JsonKey`(name: "...") and re-run code
generation.
In `@lib/api/recommend/entity/recommend_resource_entity.g.dart`:
- Around line 20-27: Add explicitToJson: true to the JsonSerializable
annotation(s) for the affected classes so nested objects are serialized via
their toJson methods (e.g., annotate RecommendResourceEntity with
`@JsonSerializable`(explicitToJson: true) and do the same for nested types if
needed such as RecommendResourceRecommend and
RecommendResourceRecommendCreator), then re-run the code generator
(build_runner) so the generated _$RecommendResourceEntityToJson will call
.toJson() for 'recommend' and 'creator' instead of embedding Dart objects
directly.
- Around line 15-18: The generated deserializer assumes json['recommend'] is
non-nullable and will throw if absent; update the source model's field
declaration for recommend in RecommendResourceEntity (in
recommend_resource_entity.dart) to either be nullable (e.g.,
List<RecommendResourceRecommend>? recommend) or provide a default via
JsonKey(defaultValue: <RecommendResourceRecommend>[]) so the generator emits a
null-safe mapping (using (json['recommend'] as List<dynamic>?)?.map(...) or a ??
[] fallback); then re-run code generation (build_runner) to regenerate
recommend_resource_entity.g.dart.
- Around line 77-78: The generated deserialization uses (json['avatarImgId'] as
num?)?.toInt() for avatarImgId and backgroundImgId which causes precision loss
on Dart web; update the source model (the class that generates
recommend_resource_entity.g.dart) to read these IDs from avatarImgIdStr and
backgroundImgIdStr instead and store them as String or BigInt (e.g. change the
field types for avatarImgId/backgroundImgId or add new fields
avatarImgIdStr/backgroundImgIdStr with `@JsonKey`(name:
'avatarImgIdStr')/@JsonKey(name: 'backgroundImgIdStr') as appropriate), then
re-run json_serializable to regenerate recommend_resource_entity.g.dart so
deserialization uses the string-based values and avoids numeric truncation.
In `@lib/api/recommend/entity/recommend_song_entity.dart`:
- Around line 1-4: The JSON key mapping regressed because the json_serializable
generator is ignoring the legacy `@JSONField` annotations; update the model class
(RecommendSongEntity) to annotate the Dart fields that must map to snake_case
API keys (e.g., sId and picStr) with JsonKey(name: 's_id') and JsonKey(name:
'pic_str') respectively (and remove or replace any lingering `@JSONField`
annotations), then re-run the code generator (build_runner) to regenerate
recommend_song_entity.g.dart so the generated toJson/fromJson use the correct
API keys.
In `@lib/api/song/entity/new_song_entity.g.dart`:
- Around line 247-257: Change the volumeDelta field from int? to double? on the
audio quality classes (NewSongDataHMusic, NewSongDataMMusic, NewSongDataLMusic,
NewSongDataBMusic) in lib/api/song/entity/new_song_entity.dart, then re-run
build_runner to regenerate new_song_entity.g.dart so the deserializer uses
(json['volumeDelta'] as num?)?.toDouble() instead of .toInt(); this preserves
fractional dB values and prevents silent truncation.
In `@lib/api/song/entity/song_detail_entity.g.dart`:
- Around line 67-68: The generated code reads sId from the wrong JSON key; open
song_detail_entity.dart and add a JsonKey mapping for the sId field (e.g.,
annotate the sId property with `@JsonKey`(name: 's_id')) so the model expects the
correct key, then re-run the code generator (build_runner/Equivalent) to
regenerate song_detail_entity.g.dart and confirm the generated line uses
json['s_id'] for sId.
In `@lib/api/top/entity/top_artist_entity.dart`:
- Around line 1-4: The class field annotations using `@JSONField` are incompatible
with json_serializable; replace the `@JSONField` annotations on the picidStr and
img1v1idStr fields with `@JsonKey`(name: 'picId_str') and `@JsonKey`(name:
'img1v1Id_str') respectively (keep the existing import of
package:json_annotation/json_annotation.dart and remove or ignore the custom
json_field import if unused) so the generated mapper reads the correct JSON keys
for those fields in the TopArtistEntity (and then re-run build_runner to
regenerate top_artist_entity.g.dart).
In `@lib/api/user/entity/login_entity.dart`:
- Around line 79-80: The field annotation `@JSONField` on avatarimgIdStr is from
the old codegen and is ignored by the current `@JsonSerializable` system; replace
`@JSONField`(name: "avatarImgId_str") with `@JsonKey`(name: "avatarImgId_str") so
the generated _$LoginProfileFromJson maps to the correct JSON key, and
remove/replace any unused import for the old FlutterJsonBeanFactory if present;
ensure package:json_annotation/json_annotation.dart is imported so `@JsonKey` is
recognized.
In `@lib/api/user/user_api.dart`:
- Line 62: The JSON payloads built in qrCodeKey, checkQrCode, and qrCodeLogin
use the misspelled key 'timerstamp' instead of 'timestamp'; confirm whether the
server expects the typo—if it's a bug, rename the key to 'timestamp' in all
three methods (qrCodeKey, checkQrCode, qrCodeLogin); if the server requires
'timerstamp', add a short inline comment above each payload construction
explaining that the misspelling is intentional and tied to server compatibility
to avoid accidental future changes.
- Around line 111-114: Remove the blanket try/catch that uses print() in the QR
code login flow (the catch block in lib/api/user/user_api.dart) and either let
exceptions propagate like the other mixin methods (loginCellPhone, checkQrCode)
or catch only expected errors and rethrow unexpected ones; replace any stdout
prints with proper logging if you must handle specific cases, and ensure callers
can distinguish network/JSON/“not-yet-scanned” errors rather than receiving a
silent null.
In `@lib/common/music_api.dart`:
- Around line 56-64: The PrettyDioLogger is currently configured to log request
headers which will expose the injected Cookie header; update the interceptor
setup on _dio.interceptors to avoid logging sensitive headers by either
disabling requestHeader in PrettyDioLogger (set requestHeader: false) or add a
small sanitizer interceptor before PrettyDioLogger that strips/masks the
"Cookie" header from RequestOptions.headers; adjust uses of PrettyDioLogger (the
instantiation with requestHeader/requestBody/responseBody options) so headers
are not emitted while preserving body/error logging.
---
Outside diff comments:
In `@lib/api/album/entity/album_info_entity.dart`:
- Around line 98-99: The `@JSONField` annotations are ignored by json_serializable
so fields deserialize with wrong keys; replace each `@JSONField`(name: "...") with
`@JsonKey`(name: '...') on the affected fields—AlbumInfoSongsAl.picStr,
AlbumInfoAlbum.picidStr, AlbumInfoAlbumArtists.img1v1idStr,
AlbumInfoAlbumArtist.picidStr, and AlbumInfoAlbumArtist.img1v1idStr—and then
regenerate the generated code by running dart run build_runner build
--delete-conflicting-outputs.
In `@lib/api/album/entity/new_album_entity.dart`:
- Around line 53-54: Replace legacy `@JSONField` annotations with
json_serializable's `@JsonKey` and ensure the name mapping matches the snake_case
API keys (e.g., change the field annotation on String? picidStr from
`@JSONField`(name: "picId_str") to `@JsonKey`(name: "picId_str")); update all other
occurrences of `@JSONField` across entity classes (e.g., in new_album_entity.dart,
album_info_entity.dart, new_song_entity.dart) and add/import package:
json_annotation/json_annotation.dart if missing, then re-run the build_runner
code generation to regenerate *.g.dart files so the deserialization reads
json['picId_str'] correctly.
In `@lib/api/playlist/entity/create_playlist_entity.dart`:
- Around line 65-66: The `@JSONField` annotation on the field coverimgidStr is not
recognized by json_serializable; replace `@JSONField`(name: "coverImgId_str") with
`@JsonKey`(name: "coverImgId_str") and ensure the file imports the json_annotation
package (import 'package:json_annotation/json_annotation.dart';) so
json_serializable will generate the correct key mapping for the field in
CreatePlaylistEntity (and update any other fields using `@JSONField` similarly).
In `@lib/api/song/entity/new_song_entity.dart`:
- Around line 166-167: Replace the incorrect `@JSONField` usages with
json_serializable's `@JsonKey` for the four fields so the generated JSON keys
match the desired names: update NewSongDataArtists.img1v1idStr,
NewSongDataAlbum.picidStr, NewSongDataAlbumArtists.img1v1idStr, and
NewSongDataAlbumArtist.img1v1idStr to use `@JsonKey`(name: "img1v1Id_str") or
`@JsonKey`(name: "picId_str") as appropriate; ensure the json_annotation import is
present so the generator recognizes `@JsonKey` and then re-run code generation.
In `@lib/api/song/entity/song_detail_entity.dart`:
- Around line 54-55: The sId field uses the `@JSONField`(name: "s_id") annotation
which json_serializable ignores, so deserialization looks for json['sId'] and
yields null; update the Dart model to use the json_serializable-supported
annotation (e.g. `@JsonKey`(name: 's_id')) on the int? sId field in
song_detail_entity.dart and then regenerate the generated file
(song_detail_entity.g.dart) so the generated fromJson/toJson use 's_id'
correctly.
In `@lib/api/user/entity/user_playlist_entity.dart`:
- Around line 64-65: Replace the unrecognized `@JSONField` annotations with
`@JsonKey` from json_annotation for the fields coverimgidStr and avatarimgidStr so
json_serializable generates the correct JSON names; specifically, update the
annotations on the String? coverimgidStr and String? avatarimgidStr members to
`@JsonKey`(name: 'coverImgId_str') and `@JsonKey`(name: 'avatarImgId_str')
respectively and ensure json_annotation is imported so the generated code maps
to the exact camelCase+suffix keys.
In `@pubspec.yaml`:
- Around line 9-25: The pubspec currently lists json_serializable and
build_runner under dev_dependencies but the library code imports json_annotation
at runtime; update the pubspec so json_annotation is added to the regular
dependencies section (not dev_dependencies), e.g. add the package name
"json_annotation" with a compatible version alongside other dependencies so
downstream consumers can resolve it; ensure you remove it from dev_dependencies
if present and run flutter pub get to confirm resolution.
---
Duplicate comments:
In `@lib/api/user/entity/bool_entity.dart`:
- Around line 1-4: The file contains an unused import of
package:bujuan_music_api/generated/json/base/json_field.dart in
bool_entity.dart; either remove that import line (since there are no `@JSONField`
annotations) or if you intended to use JSONField, add the appropriate `@JSONField`
annotations to the relevant class/fields (e.g., the BoolEntity class and its
members) and then regenerate the part file; update the import accordingly.
---
Nitpick comments:
In `@lib/api/song/entity/new_song_entity.g.dart`:
- Around line 72-108: The generated toJson (e.g., _$NewSongDataToJson) is
embedding nested object instances (fields like privilege, artists, album,
hMusic, mMusic, lMusic, bMusic, etc.) instead of their Maps; fix by annotating
the corresponding parent classes in new_song_entity.dart (e.g., class
NewSongData and any nested entity classes referenced) with
`@JsonSerializable`(explicitToJson: true), then re-run the code generator
(build_runner) to regenerate the *.g.dart so the generated toJson calls use
.toJson() for nested objects; ensure you update all affected classes mentioned
in the review so sections at lines ~72-108, 146-175 and 355-381 are regenerated
correctly.
In `@lib/api/song/entity/song_url_entity.dart`:
- Around line 1-4: The import
'package:bujuan_music_api/generated/json/base/json_field.dart' is unused in this
file; remove that import line from lib/api/song/entity/song_url_entity.dart so
only the needed imports remain (retain imports for json_annotation, dart:convert
and the part 'song_url_entity.g.dart'); update any analyzer/formatting by
running the Dart analyzer/formatter to ensure no remaining references to
JSONField or unused-import warnings for the SongUrlEntity related code.
In `@lib/api/user/entity/login_entity.dart`:
- Around line 1-5: The file imports an unused legacy annotation package (import
'package:bujuan_music_api/generated/json/base/json_field.dart') and still uses
`@JSONField`; update the class to use `@JsonKey` instead of `@JSONField` (replace the
annotation on the login entity) and then remove the now-dead import statement;
ensure only 'package:json_annotation/json_annotation.dart' remains and
regenerate/verify generated files for the changes to login_entity (look for
`@JSONField`, `@JsonKey`, and the import at the top to locate the spots to edit).
In `@lib/api/user/entity/login_entity.g.dart`:
- Around line 26-37: The generated JSON serializers _$LoginEntityToJson and
_$LoginProfileToJson are leaving nested fields (LoginEntity.account,
LoginEntity.profile, LoginEntity.bindings and LoginProfile.experts) as raw Dart
objects; update the source model annotation in login_entity.dart to enable
explicitToJson: true for the JsonSerializable on LoginEntity (and LoginProfile
if separate), re-run the code generator to regenerate _$LoginEntityToJson and
_$LoginProfileToJson so nested objects are serialized via their toJson() methods
instead of being embedded as raw objects.
In `@lib/api/user/user_api.dart`:
- Line 7: Remove the trailing inline comment from the import statement that
brings in qr_check_result_entity (import
'package:bujuan_music_api/api/user/entity/qr_check_result_entity.dart';) so the
import stands alone without the debug/dev comment "// 新增"; simply delete the
comment text and keep the import unchanged.
- Around line 88-115: The qrCodeLogin method bypasses the shared HTTP
abstraction by calling BujuanMusicManager().dio.post directly and doing manual
JSON parsing and cookie extraction; change qrCodeLogin to use
BujuanMusicManager.post<T>(...) so it benefits from unified
parsing/interceptors, or add a new BujuanMusicManager.postRaw(...) (or a flag on
post) that returns the raw Response so qrCodeLogin can call that, parse the body
into QrCheckResultEntity via the existing JSON parsing path, and extract cookies
from response.headers['set-cookie'] to set result.cookie; update qrCodeLogin to
remove the manual jsonDecode branch and rely on the manager's parsing behavior.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (24)
lib/generated/json/album_info_entity.g.dartis excluded by!**/generated/**lib/generated/json/base/json_field.dartis excluded by!**/generated/**lib/generated/json/bool_entity.g.dartis excluded by!**/generated/**lib/generated/json/catalogue_entity.g.dartis excluded by!**/generated/**lib/generated/json/create_playlist_entity.g.dartis excluded by!**/generated/**lib/generated/json/high_quality_tags_entity.g.dartis excluded by!**/generated/**lib/generated/json/like_list_entity.g.dartis excluded by!**/generated/**lib/generated/json/login_entity.g.dartis excluded by!**/generated/**lib/generated/json/mv_url_entity.g.dartis excluded by!**/generated/**lib/generated/json/new_album_entity.g.dartis excluded by!**/generated/**lib/generated/json/new_song_entity.g.dartis excluded by!**/generated/**lib/generated/json/playlist_detail_entity.g.dartis excluded by!**/generated/**lib/generated/json/qr_check_entity.g.dartis excluded by!**/generated/**lib/generated/json/qrcode_key_entity.g.dartis excluded by!**/generated/**lib/generated/json/recommend_resource_entity.g.dartis excluded by!**/generated/**lib/generated/json/recommend_song_entity.g.dartis excluded by!**/generated/**lib/generated/json/song_detail_entity.g.dartis excluded by!**/generated/**lib/generated/json/song_like_check_entity.g.dartis excluded by!**/generated/**lib/generated/json/song_quality_detail_entity.g.dartis excluded by!**/generated/**lib/generated/json/song_url_entity.g.dartis excluded by!**/generated/**lib/generated/json/string_entity.g.dartis excluded by!**/generated/**lib/generated/json/top_artist_entity.g.dartis excluded by!**/generated/**lib/generated/json/user_info_entity.g.dartis excluded by!**/generated/**lib/generated/json/user_playlist_entity.g.dartis excluded by!**/generated/**
📒 Files selected for processing (53)
flutterlib/api/album/entity/album_info_entity.dartlib/api/album/entity/album_info_entity.g.dartlib/api/album/entity/new_album_entity.dartlib/api/album/entity/new_album_entity.g.dartlib/api/mv/entity/mv_url_entity.dartlib/api/mv/entity/mv_url_entity.g.dartlib/api/playlist/entity/catalogue_entity.dartlib/api/playlist/entity/catalogue_entity.g.dartlib/api/playlist/entity/create_playlist_entity.dartlib/api/playlist/entity/create_playlist_entity.g.dartlib/api/playlist/entity/high_quality_tags_entity.dartlib/api/playlist/entity/high_quality_tags_entity.g.dartlib/api/playlist/entity/playlist_detail_entity.dartlib/api/playlist/entity/playlist_detail_entity.g.dartlib/api/recommend/entity/recommend_resource_entity.dartlib/api/recommend/entity/recommend_resource_entity.g.dartlib/api/recommend/entity/recommend_song_entity.dartlib/api/recommend/entity/recommend_song_entity.g.dartlib/api/song/entity/new_song_entity.dartlib/api/song/entity/new_song_entity.g.dartlib/api/song/entity/song_detail_entity.dartlib/api/song/entity/song_detail_entity.g.dartlib/api/song/entity/song_like_check_entity.dartlib/api/song/entity/song_like_check_entity.g.dartlib/api/song/entity/song_quality_detail_entity.dartlib/api/song/entity/song_quality_detail_entity.g.dartlib/api/song/entity/song_url_entity.dartlib/api/song/entity/song_url_entity.g.dartlib/api/top/entity/top_artist_entity.dartlib/api/top/entity/top_artist_entity.g.dartlib/api/user/entity/bool_entity.dartlib/api/user/entity/bool_entity.g.dartlib/api/user/entity/like_list_entity.dartlib/api/user/entity/like_list_entity.g.dartlib/api/user/entity/login_entity.dartlib/api/user/entity/login_entity.g.dartlib/api/user/entity/qr_check_entity.dartlib/api/user/entity/qr_check_entity.g.dartlib/api/user/entity/qr_check_result_entity.dartlib/api/user/entity/qr_check_result_entity.g.dartlib/api/user/entity/qrcode_key_entity.dartlib/api/user/entity/qrcode_key_entity.g.dartlib/api/user/entity/string_entity.dartlib/api/user/entity/string_entity.g.dartlib/api/user/entity/user_info_entity.dartlib/api/user/entity/user_info_entity.g.dartlib/api/user/entity/user_playlist_entity.dartlib/api/user/entity/user_playlist_entity.g.dartlib/api/user/user_api.dartlib/bujuan_music_api.dartlib/common/music_api.dartpubspec.yaml
| @@ -0,0 +1 @@ | |||
| Subproject commit 90673a4eef275d1a6692c26ac80d6d746d41a73a | |||
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Flutter commit 90673a4eef275d1a6692c26ac80d6d746d41a73a version release tag
💡 Result:
Commit 90673a4eef275d1a6692c26ac80d6d746d41a73a corresponds to the Flutter 3.41.2 (stable) release tag. [1][2]
Sources: [1] commit page, [2] tags listing showing 3.41.2 → 90673a4e.
🏁 Script executed:
# Search for any git history or context about this change
git log --oneline -20 --all -- flutter 2>/dev/null || echo "No git history available"
# Look for any PR description or motivation in common places
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "COMMIT_EDITMSG" \) -exec grep -l "90673a4\|flutter.*submodule" {} \; 2>/dev/null | head -5
# Check if there's any recent context in the repo root
ls -la | grep -i readmeRepository: 2697a/bujuan_music_api
Length of output: 152
🏁 Script executed:
# Find and examine pubspec.yaml to see what dependencies might require Flutter 3.41.2
fd pubspec.yaml -type f
# If found, show its contents
if [ -f pubspec.yaml ]; then
echo "=== pubspec.yaml ==="
cat pubspec.yaml
fiRepository: 2697a/bujuan_music_api
Length of output: 2019
🏁 Script executed:
# Also check git log for the pubspec.yaml change to see commit message
git log --oneline --all -- "**/pubspec.yaml" 2>/dev/null | head -10 || echo "Git log not available"
# Try to find any change summary or PR notes
git show e88b5bc 2>/dev/null | head -50 || echo "Commit details not available"Repository: 2697a/bujuan_music_api
Length of output: 1196
Document the rationale for the Flutter 3.41.2 submodule bump or revert if unintentional.
The submodule was updated to commit 90673a4eef275d1a6692c26ac80d6d746d41a73a (Flutter 3.41.2 stable). While this is a legitimate release, the PR description makes no mention of a Flutter version upgrade, and the commit message ("Update pubspec.yaml") provides no rationale. Additionally, pubspec.yaml does not specify a minimum Flutter version constraint, implying earlier versions should remain compatible.
If this bump is intentional, document the reason (e.g., required for a specific API or dependency). If accidental, revert to the previously pinned commit.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@flutter` at line 1, The Flutter submodule was advanced to commit
90673a4eef275d1a6692c26ac80d6d746d41a73a (Flutter 3.41.2) without explanation;
either document the upgrade rationale in the PR and commit message (e.g.,
required API, dependency, or bugfix) and add a minimum SDK constraint in
pubspec.yaml (e.g., environment.sdk / flutter minimum version) to prevent
accidental use on older toolchains, or if the bump was unintentional revert the
flutter submodule to the previous pinned commit and update the PR description to
state that no Flutter version change is intended.
| AlbumInfoSongsAl _$AlbumInfoSongsAlFromJson(Map<String, dynamic> json) => | ||
| AlbumInfoSongsAl() | ||
| ..id = (json['id'] as num?)?.toInt() | ||
| ..name = json['name'] as String? | ||
| ..picUrl = json['picUrl'] as String? | ||
| ..picStr = json['picStr'] as String? | ||
| ..pic = (json['pic'] as num?)?.toInt(); | ||
|
|
||
| Map<String, dynamic> _$AlbumInfoSongsAlToJson(AlbumInfoSongsAl instance) => | ||
| <String, dynamic>{ | ||
| 'id': instance.id, | ||
| 'name': instance.name, | ||
| 'picUrl': instance.picUrl, | ||
| 'picStr': instance.picStr, | ||
| 'pic': instance.pic, | ||
| }; |
There was a problem hiding this comment.
Wrong JSON key strings — downstream effect of ignored @JSONField annotations.
picStr, picidStr, and img1v1idStr are read/written using the Dart field names (e.g. json['picStr'], json['picidStr'], json['img1v1idStr']) instead of the intended API key names (pic_str, picId_str, img1v1Id_str). This affects the fromJson reads (Lines 138, 366, 420, 457, 461) and the toJson writes (Lines 147, 400, 438, 479, 481).
Root cause is in album_info_entity.dart — replace @JSONField with @JsonKey and regenerate this file. See the comment on album_info_entity.dart.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/album/entity/album_info_entity.g.dart` around lines 133 - 148, The
generated serialization uses Dart field names for keys (e.g.,
AlbumInfoSongsAl.picStr, picidStr, img1v1idStr) instead of the API keys
(pic_str, picId_str, img1v1Id_str), causing incorrect fromJson/toJson behavior;
to fix, update the model annotations in album_info_entity.dart by replacing the
incorrect `@JSONField` annotations with the proper JsonSerializable-compatible
`@JsonKey`(name: '...') attributes for the fields (e.g., use `@JsonKey`(name:
'pic_str') for picStr, `@JsonKey`(name: 'picId_str') for picidStr, `@JsonKey`(name:
'img1v1Id_str') for img1v1idStr), then re-run the code generator to regenerate
the _$AlbumInfoSongsAlFromJson/_$AlbumInfoSongsAlToJson and other affected
serializers so they read/write the correct JSON keys.
| import 'package:json_annotation/json_annotation.dart'; | ||
| import 'package:bujuan_music_api/generated/json/base/json_field.dart'; | ||
| import 'package:bujuan_music_api/generated/json/playlist_detail_entity.g.dart'; | ||
| import 'dart:convert'; | ||
| export 'package:bujuan_music_api/generated/json/playlist_detail_entity.g.dart'; | ||
| part 'playlist_detail_entity.g.dart'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Checking if playlist_detail_entity.dart exists ==="
if [ -f "lib/api/playlist/entity/playlist_detail_entity.dart" ]; then
echo "File found"
else
echo "File not found, searching for it..."
find . -name "playlist_detail_entity.dart" -type f
fi
echo
echo "=== First 50 lines of playlist_detail_entity.dart ==="
head -50 lib/api/playlist/entity/playlist_detail_entity.dart || echo "Cannot read file"Repository: 2697a/bujuan_music_api
Length of output: 1423
🏁 Script executed:
#!/bin/bash
echo "=== Checking for `@JSONField` annotations in source ==="
rg -n 'JSONField\(' lib/api/playlist/entity/playlist_detail_entity.dart || echo "No `@JSONField` found"
echo
echo "=== Checking for generated file ==="
if [ -f "lib/api/playlist/entity/playlist_detail_entity.g.dart" ]; then
echo "Generated file exists, checking size..."
wc -l lib/api/playlist/entity/playlist_detail_entity.g.dart
else
echo "Generated file does not exist"
fi
echo
echo "=== Checking for aliased keys in generated code ==="
rg '"(coverImgId_str|avatarImgId_str|s_id|pic_str)"' lib/api/playlist/entity/playlist_detail_entity.g.dart || echo "No aliased keys found in generated code"Repository: 2697a/bujuan_music_api
Length of output: 531
🏁 Script executed:
#!/bin/bash
echo "=== Full content of playlist_detail_entity.dart ==="
cat lib/api/playlist/entity/playlist_detail_entity.dart
echo
echo "=== Content of generated file (first 100 lines) ==="
head -100 lib/api/playlist/entity/playlist_detail_entity.g.dart || echo "Cannot read generated file"Repository: 2697a/bujuan_music_api
Length of output: 18075
Replace @JSONField with @JsonKey for aliased fields—json_serializable doesn't recognize the custom annotations.
The generated code at line 49 (..coverimgidStr = json['coverimgidStr'] as String?) reads from the Dart field name coverimgidStr, not the aliased JSON key coverImgId_str. This occurs on 5 fields in this file:
coverImgId_str(PlaylistDetailPlaylist, line 37)avatarImgId_str(PlaylistDetailPlaylistSubscribers, line 139)avatarImgId_str(PlaylistDetailPlaylistCreator, line 186)s_id(PlaylistDetailPlaylistTracks, line 249)pic_str(PlaylistDetailPlaylistTracksAl, line 309)
Without this change, JSON responses with these aliased keys will fail to deserialize.
Fix
Replace @JSONField(name: "...") with @JsonKey(name: "...") on all 5 fields.
-import 'package:bujuan_music_api/generated/json/base/json_field.dart';
-@JSONField(name: "coverImgId_str")
+@JsonKey(name: "coverImgId_str")
String? coverimgidStr = '';
-@JSONField(name: "avatarImgId_str")
+@JsonKey(name: "avatarImgId_str")
String? avatarimgidStr = '';
-@JSONField(name: "s_id")
+@JsonKey(name: "s_id")
int? sId = 0;
-@JSONField(name: "pic_str")
+@JsonKey(name: "pic_str")
String? picStr = '';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/playlist/entity/playlist_detail_entity.dart` around lines 1 - 4, The
custom `@JSONField` annotations are not recognized by json_serializable so the
aliased JSON keys aren’t used; replace each `@JSONField`(name: "...") with
`@JsonKey`(name: "...") on the listed fields so the generated code uses the
correct JSON names: change the annotation on coverImgId_str in class
PlaylistDetailPlaylist, avatarImgId_str in PlaylistDetailPlaylistSubscribers,
avatarImgId_str in PlaylistDetailPlaylistCreator, s_id in
PlaylistDetailPlaylistTracks, and pic_str in PlaylistDetailPlaylistTracksAl to
use `@JsonKey`(name: "...") and re-run code generation.
| ..recommend = (json['recommend'] as List<dynamic>) | ||
| .map((e) => | ||
| RecommendResourceRecommend.fromJson(e as Map<String, dynamic>)) | ||
| .toList(); |
There was a problem hiding this comment.
recommend list deserialization will throw if the field is null or absent
Unlike expertTags (line 81, which uses ?.map), json['recommend'] is cast directly as a non-nullable List<dynamic>. Any API response that omits or nulls this field (e.g., an error state or empty result) throws a runtime exception.
Since this is generated code, the fix belongs in the source class annotation/field declaration in recommend_resource_entity.dart. If the field is intended to be non-nullable, ensure the API contract guarantees its presence; otherwise, declare it nullable or provide a default.
🛡️ Expected generated output after fixing the source field
- ..recommend = (json['recommend'] as List<dynamic>)
- .map((e) =>
- RecommendResourceRecommend.fromJson(e as Map<String, dynamic>))
- .toList();
+ ..recommend = (json['recommend'] as List<dynamic>?)
+ ?.map((e) =>
+ RecommendResourceRecommend.fromJson(e as Map<String, dynamic>))
+ .toList() ?? [];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ..recommend = (json['recommend'] as List<dynamic>) | |
| .map((e) => | |
| RecommendResourceRecommend.fromJson(e as Map<String, dynamic>)) | |
| .toList(); | |
| ..recommend = (json['recommend'] as List<dynamic>?) | |
| ?.map((e) => | |
| RecommendResourceRecommend.fromJson(e as Map<String, dynamic>)) | |
| .toList() ?? []; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/recommend/entity/recommend_resource_entity.g.dart` around lines 15 -
18, The generated deserializer assumes json['recommend'] is non-nullable and
will throw if absent; update the source model's field declaration for recommend
in RecommendResourceEntity (in recommend_resource_entity.dart) to either be
nullable (e.g., List<RecommendResourceRecommend>? recommend) or provide a
default via JsonKey(defaultValue: <RecommendResourceRecommend>[]) so the
generator emits a null-safe mapping (using (json['recommend'] as
List<dynamic>?)?.map(...) or a ?? [] fallback); then re-run code generation
(build_runner) to regenerate recommend_resource_entity.g.dart.
| Map<String, dynamic> _$RecommendResourceEntityToJson( | ||
| RecommendResourceEntity instance) => | ||
| <String, dynamic>{ | ||
| 'code': instance.code, | ||
| 'featureFirst': instance.featureFirst, | ||
| 'haveRcmdSongs': instance.haveRcmdSongs, | ||
| 'recommend': instance.recommend, | ||
| }; |
There was a problem hiding this comment.
Nested objects are not serialized to maps in toJson() — explicitToJson: true is missing
'recommend': instance.recommend (line 26) stores a List<RecommendResourceRecommend> of Dart objects directly, and 'creator': instance.creator (line 57) stores a RecommendResourceRecommendCreator object directly. jsonEncode(entity.toJson()) will throw an Unhandled Exception: Converting object to an encodable object failed at runtime because the JSON encoder cannot handle these opaque Dart objects.
This is a json_serializable default behavior: nested .toJson() calls are only emitted when explicitToJson: true is set on the source annotation. Fix in recommend_resource_entity.dart:
🐛 Fix in the source class (triggers regeneration of this file)
-@JsonSerializable()
+@JsonSerializable(explicitToJson: true)
class RecommendResourceEntity { ... }
-@JsonSerializable()
+@JsonSerializable(explicitToJson: true)
class RecommendResourceRecommend { ... }After regeneration, the generated output should look like:
-'recommend': instance.recommend,
+'recommend': instance.recommend.map((e) => e.toJson()).toList(),
-'creator': instance.creator,
+'creator': instance.creator?.toJson(),Also applies to: 47-61
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/recommend/entity/recommend_resource_entity.g.dart` around lines 20 -
27, Add explicitToJson: true to the JsonSerializable annotation(s) for the
affected classes so nested objects are serialized via their toJson methods
(e.g., annotate RecommendResourceEntity with `@JsonSerializable`(explicitToJson:
true) and do the same for nested types if needed such as
RecommendResourceRecommend and RecommendResourceRecommendCreator), then re-run
the code generator (build_runner) so the generated
_$RecommendResourceEntityToJson will call .toJson() for 'recommend' and
'creator' instead of embedding Dart objects directly.
| import 'package:json_annotation/json_annotation.dart'; | ||
| import 'package:bujuan_music_api/generated/json/base/json_field.dart'; | ||
| import 'package:bujuan_music_api/generated/json/top_artist_entity.g.dart'; | ||
| import 'dart:convert'; | ||
| export 'package:bujuan_music_api/generated/json/top_artist_entity.g.dart'; | ||
| part 'top_artist_entity.g.dart'; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Checking if files exist ==="
ls -la lib/api/top/entity/top_artist_entity.dart 2>/dev/null || echo "File not found"
ls -la lib/api/top/entity/top_artist_entity.g.dart 2>/dev/null || echo "Generated file not found"
echo
echo "=== Lines 1-4 of source file ==="
head -4 lib/api/top/entity/top_artist_entity.dart
echo
echo "=== Checking for JSONField vs JsonKey annotations ==="
echo "Source file - JSONField usage:"
rg -n '@JSONField\(name:' lib/api/top/entity/top_artist_entity.dart || echo "No `@JSONField` found"
echo
echo "Source file - JsonKey usage:"
rg -n '@JsonKey\(name:' lib/api/top/entity/top_artist_entity.dart || echo "No `@JsonKey` found"
echo
echo "=== Checking specific lines mentioned (14-16, 51-53) ==="
echo "Lines 14-16:"
sed -n '14,16p' lib/api/top/entity/top_artist_entity.dart
echo
echo "Lines 51-53:"
sed -n '51,53p' lib/api/top/entity/top_artist_entity.dart
echo
echo "=== Generated mapper key usage ==="
if [ -f lib/api/top/entity/top_artist_entity.g.dart ]; then
echo "Keys referenced in generated file:"
rg -n '"(picId_str|img1v1Id_str|picidStr|img1v1idStr)"' lib/api/top/entity/top_artist_entity.g.dart || echo "No matching keys found"
else
echo "Generated file does not exist"
fiRepository: 2697a/bujuan_music_api
Length of output: 1210
🏁 Script executed:
#!/bin/bash
echo "=== Source file lines 38-45 (context around line 40) ==="
sed -n '38,45p' lib/api/top/entity/top_artist_entity.dart
echo
echo "=== Full source file ==="
cat -n lib/api/top/entity/top_artist_entity.dart
echo
echo "=== Full generated file ==="
cat -n lib/api/top/entity/top_artist_entity.g.dartRepository: 2697a/bujuan_music_api
Length of output: 5386
Replace @JSONField with @JsonKey for json_serializable compatibility.
The @JSONField annotations on lines 40 and 42 are not recognized by json_serializable. The generated mapper reads picidStr and img1v1idStr keys instead of the intended picId_str and img1v1Id_str, breaking JSON deserialization for those fields.
Proposed fix
import 'package:json_annotation/json_annotation.dart';
-import 'package:bujuan_music_api/generated/json/base/json_field.dart';
- `@JSONField`(name: "picId_str")
+ `@JsonKey`(name: "picId_str")
String? picidStr = '';
- `@JSONField`(name: "img1v1Id_str")
+ `@JsonKey`(name: "img1v1Id_str")
String? img1v1idStr = '';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/top/entity/top_artist_entity.dart` around lines 1 - 4, The class
field annotations using `@JSONField` are incompatible with json_serializable;
replace the `@JSONField` annotations on the picidStr and img1v1idStr fields with
`@JsonKey`(name: 'picId_str') and `@JsonKey`(name: 'img1v1Id_str') respectively
(keep the existing import of package:json_annotation/json_annotation.dart and
remove or ignore the custom json_field import if unused) so the generated mapper
reads the correct JSON keys for those fields in the TopArtistEntity (and then
re-run build_runner to regenerate top_artist_entity.g.dart).
| @JSONField(name: "avatarImgId_str") | ||
| String? avatarimgIdStr; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd 'login_entity.g.dart' -type fRepository: 2697a/bujuan_music_api
Length of output: 236
🏁 Script executed:
fd 'login_entity.g.dart' --type fRepository: 2697a/bujuan_music_api
Length of output: 105
🏁 Script executed:
cat lib/api/user/entity/login_entity.g.dart | grep -A 5 -B 5 'avatarimgIdStr'Repository: 2697a/bujuan_music_api
Length of output: 1089
🏁 Script executed:
sed -n '75,85p' lib/api/user/entity/login_entity.dartRepository: 2697a/bujuan_music_api
Length of output: 305
@JSONField is not recognized by json_serializable; use @JsonKey instead.
@JSONField comes from the old FlutterJsonBeanFactory/custom codegen system (imported on Line 2). Since this class now uses @JsonSerializable() with generated _$LoginProfileFromJson, only @JsonKey annotations are honored. The generated code maps this field to JSON key "avatarimgIdStr" instead of "avatarImgId_str", causing deserialization to fail for the intended JSON key.
🐛 Proposed fix
- `@JSONField`(name: "avatarImgId_str")
+ `@JsonKey`(name: 'avatarImgId_str')
String? avatarimgIdStr;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @JSONField(name: "avatarImgId_str") | |
| String? avatarimgIdStr; | |
| `@JsonKey`(name: 'avatarImgId_str') | |
| String? avatarimgIdStr; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/user/entity/login_entity.dart` around lines 79 - 80, The field
annotation `@JSONField` on avatarimgIdStr is from the old codegen and is ignored
by the current `@JsonSerializable` system; replace `@JSONField`(name:
"avatarImgId_str") with `@JsonKey`(name: "avatarImgId_str") so the generated
_$LoginProfileFromJson maps to the correct JSON key, and remove/replace any
unused import for the old FlutterJsonBeanFactory if present; ensure
package:json_annotation/json_annotation.dart is imported so `@JsonKey` is
recognized.
| /// | ||
| /// [type] 类型(可选,默认为 3) | ||
| Future<QrcodeKeyEntity?> qrCodeKey({int type = 1}) async { | ||
| final data = {'type': type, 'timerstamp': '${DateTime.now()}'}; |
There was a problem hiding this comment.
Typo: 'timerstamp' — is this intentional for server compatibility?
This key appears across qrCodeKey (line 62), checkQrCode (line 77), and qrCodeLogin (line 87). If the server genuinely expects timerstamp, please add a brief comment to prevent future "fixes" that would break the API. If it's a bug, it should be timestamp.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/user/user_api.dart` at line 62, The JSON payloads built in qrCodeKey,
checkQrCode, and qrCodeLogin use the misspelled key 'timerstamp' instead of
'timestamp'; confirm whether the server expects the typo—if it's a bug, rename
the key to 'timestamp' in all three methods (qrCodeKey, checkQrCode,
qrCodeLogin); if the server requires 'timerstamp', add a short inline comment
above each payload construction explaining that the misspelling is intentional
and tied to server compatibility to avoid accidental future changes.
| } catch (e) { | ||
| print('QR code login error: $e'); | ||
| return null; | ||
| } |
There was a problem hiding this comment.
Avoid print() in library code; silent catch-all hides failures.
print() in a library pollutes the consumer's stdout and cannot be disabled. More importantly, the blanket catch (e) returns null for every failure — network timeouts, JSON parse errors, and legitimate "not-yet-scanned" responses are all indistinguishable to the caller.
Consider either:
- Removing the
try/catchand letting exceptions propagate (consistent with other methods in this mixin), or - Catching only expected cases and rethrowing unexpected ones.
Proposed fix — remove blanket catch, let exceptions propagate
- } catch (e) {
- print('QR code login error: $e');
- return null;
- }
+ } on FormatException {
+ return null;
+ }Or remove the try/catch entirely to stay consistent with loginCellPhone, checkQrCode, etc.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| } catch (e) { | |
| print('QR code login error: $e'); | |
| return null; | |
| } | |
| } on FormatException { | |
| return null; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/api/user/user_api.dart` around lines 111 - 114, Remove the blanket
try/catch that uses print() in the QR code login flow (the catch block in
lib/api/user/user_api.dart) and either let exceptions propagate like the other
mixin methods (loginCellPhone, checkQrCode) or catch only expected errors and
rethrow unexpected ones; replace any stdout prints with proper logging if you
must handle specific cases, and ensure callers can distinguish
network/JSON/“not-yet-scanned” errors rather than receiving a silent null.
| _dio.interceptors.add(PrettyDioLogger( | ||
| requestHeader: true, | ||
| requestBody: true, | ||
| responseBody: true, | ||
| responseHeader: false, | ||
| error: true, | ||
| compact: true, | ||
| maxWidth: 200, | ||
| enabled: _debug)); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd lib/common/music_api.dartRepository: 2697a/bujuan_music_api
Length of output: 48
🏁 Script executed:
cat -n lib/common/music_api.dart | head -80Repository: 2697a/bujuan_music_api
Length of output: 3375
🌐 Web query:
PrettyDioLogger requestHeader true logs headers Cookie authentication
💡 Result:
PrettyDioLogger(requestHeader: true) only prints what’s in RequestOptions.headers (i.e., headers your Dio code can set/see). It does not guarantee you’ll see the final on-the-wire Cookie header. (pub.dev)
Why Cookie often won’t show up (especially on Flutter Web)
On the web, Cookie is a forbidden request header—the browser won’t let JavaScript (and thus Flutter Web/Dio) set or override it programmatically. So there may be nothing for PrettyDioLogger to print, even though cookies may still be handled by the browser automatically. (developer.mozilla.org)
What to do for cookie-based authentication on Web
Let the server set cookies via Set-Cookie, and tell Dio’s browser adapter to send cookies on (cross-site) requests by enabling withCredentials:
import 'package:dio/adapter_browser.dart';
import 'package:dio/dio.dart';
final dio = Dio();
final adapter = BrowserHttpClientAdapter()..withCredentials = true;
dio.httpClientAdapter = adapter;
dio.interceptors.add(PrettyDioLogger(requestHeader: true, responseHeader: true));This is the commonly used Dio-for-browser equivalent of Axios withCredentials: true. (stackoverflow.com)
If you tell me whether you’re on Flutter Web vs Android/iOS and whether the request is cross-origin, I can pinpoint exactly why the cookie isn’t appearing in your logs (vs not being sent at all).
Citations:
- 1: https://pub.dev/documentation/pretty_dio_logger/latest/pretty_dio_logger/PrettyDioLogger-class.html
- 2: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_request_header?utm_source=openai
- 3: https://stackoverflow.com/questions/69085490/what-is-the-equivalent-code-in-flutter-dio-http-compare-to-axios-withcredential
🏁 Script executed:
# Search for usage patterns of PrettyDioLogger in the codebase to understand the intent
rg "PrettyDioLogger" --type dart -B 2 -A 10Repository: 2697a/bujuan_music_api
Length of output: 709
🏁 Script executed:
# Check if this is web-only or supports mobile
rg "android|ios|mobile|platform" lib/common/music_api.dart
rg "kIsWeb" -A 2 -B 2 lib/common/music_api.dartRepository: 2697a/bujuan_music_api
Length of output: 283
🏁 Script executed:
# Check the pubspec or main init to see supported platforms
fd pubspec.yaml -x head -50Repository: 2697a/bujuan_music_api
Length of output: 1415
Do not log authentication headers (Cookie) in HTTP logger.
At Line 50 you inject Cookie into request headers, and at Line 57 requestHeader: true logs all request headers. On mobile platforms (Android/iOS) this will leak session cookies/tokens into logs. While the Cookie header cannot be logged on Flutter Web (it's a forbidden header), this package supports both mobile and web platforms.
🔧 Minimal safe change
if (_debug) {
_dio.interceptors.add(PrettyDioLogger(
- requestHeader: true,
+ requestHeader: false,
requestBody: true,
responseBody: true,
responseHeader: false,
error: true,
compact: true,
maxWidth: 200,
enabled: _debug));
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| _dio.interceptors.add(PrettyDioLogger( | |
| requestHeader: true, | |
| requestBody: true, | |
| responseBody: true, | |
| responseHeader: false, | |
| error: true, | |
| compact: true, | |
| maxWidth: 200, | |
| enabled: _debug)); | |
| _dio.interceptors.add(PrettyDioLogger( | |
| requestHeader: false, | |
| requestBody: true, | |
| responseBody: true, | |
| responseHeader: false, | |
| error: true, | |
| compact: true, | |
| maxWidth: 200, | |
| enabled: _debug)); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/common/music_api.dart` around lines 56 - 64, The PrettyDioLogger is
currently configured to log request headers which will expose the injected
Cookie header; update the interceptor setup on _dio.interceptors to avoid
logging sensitive headers by either disabling requestHeader in PrettyDioLogger
(set requestHeader: false) or add a small sanitizer interceptor before
PrettyDioLogger that strips/masks the "Cookie" header from
RequestOptions.headers; adjust uses of PrettyDioLogger (the instantiation with
requestHeader/requestBody/responseBody options) so headers are not emitted while
preserving body/error logging.
Description
This PR significantly improves the login functionality of the library:
messagefield to receive server error details (e.g., code 8860), allowing clients to display user-friendly error messages./login/qr/key,/login/qr/create,/login/qr/check) with proper cookie extraction.addCookie(String cookieStr)andclearCookies()methods that store cookies incookieJar(persistent). The previoussetCookie(memory only) is deprecated but kept for backward compatibility.partdirectives instead ofexport. Regenerated all.g.dartfiles to ensure they are in sync with the entities. Fixed missing_in private method calls.json_annotationto^4.10.0for compatibility withjson_serializable ^6.7.0.Testing
Notes
setCookiemethod is now deprecated; useaddCookieinstead (which is asynchronous, so remember toawaitit).Please review and let me know if any further adjustments are needed.
Actually, this is my first pull request and my fork may no longer be maintained.
Summary by CodeRabbit
New Features
Chores