Tiếng Việt · English · 简体中文
Tài liệu được duy trì bằng ba ngôn ngữ trên. UI Flutter hiện mặc định tiếng Việt; các widget/remote native tự chọn nhãn tiếng Việt, English hoặc 简体中文 theo ngôn ngữ hệ điều hành.
#zingChart là ứng dụng bảng xếp hạng và trình phát nhạc Local-First viết bằng Flutter. Một codebase phục vụ Android, Android TV, iOS, Web/PWA, Windows, macOS, Linux, Amazon Fire OS/Fire TV, LG webOS TV, Samsung Tizen TV và HarmonyOS phone/tablet.
Client không gọi trực tiếp upstream Zing. Tất cả dữ liệu chart và audio đi qua proxy Node/TypeScript do người triển khai tự host.
- Zing Chart realtime: thứ hạng, biến động tăng/giảm, ảnh bìa, tên bài, nghệ
sĩ, album và thời lượng theo đúng metadata chart; biểu đồ 24 giờ tương tác
bằng hover, chạm/kéo, bàn phím hoặc remote TV, có tooltip tỷ lệ và phát trực
tiếp bài đang chọn. Chart tự làm mới nền mỗi hai phút khi đang hiển thị, giữ
dữ liệu cũ và cho phép thử lại nếu mạng gián đoạn, đồng thời dừng request khi
app không hoạt động. Khám phá nhúng thêm preview
#zingchartgồm đồ thị 24 giờ và top 3, phát đúng queue BXH hoặc mở bảng đầy đủ mà không gọi endpoint mới. Hàng “Gợi ý” chính thức tải độc lập, bỏ bài trùng BXH, có link nghệ sĩ/album mở nội bộ và không gửi favorites, lịch sử hay analytics ra khỏi thiết bị. Danh sách mặc định bám Zing MP3 với top 10 và nút “Xem top 100”; queue vẫn giữ đủ BXH. Từng nghệ sĩ trong danh sách cộng tác và album là link hover/focus mở đúng nội dung chính thức; action “Thông tin” mở Song Detail mà không tự phát bài. Trong Song Detail, nghệ sĩ, nhạc sĩ và album tiếp tục mở thẳng hồ sơ/nội dung nội bộ tương ứng mà không làm gián đoạn bài đang phát hoặc thay đổi queue. Ảnh bìa hiện affordance Play/Lock/Now Playing khi hover hoặc focus. Menu bài hát được dùng thống nhất cho nút Thêm và chuột phải trên desktop: Phát ngay, Thông tin, hàng đợi, Song Radio, playlist, chia sẻ, yêu thích và mood; bài bị khóa vẫn xem/lưu được nhưng không lộ thao tác phát, queue hay Radio. - BXH Nhạc Mới theo dữ liệu phát hành hiện tại: hạng, xu hướng tăng/giảm, album, thời lượng và trạng thái quyền phát; layout riêng cho mobile, desktop và TV.
- Bảng Xếp Hạng Tuần chính thức theo Việt Nam, US-UK và K-Pop; ba card khu vực nằm ngay trong Khám phá như Zing MP3 và mở thẳng đúng BXH. Màn đầy đủ cho chọn tám tuần gần nhất, xem biến động hạng/album/thời lượng và chỉ phát các bài được phép.
- Mới Phát Hành theo catalog bài hát/album, có tab như Zing MP3, lọc Tất cả, Việt Nam, Âu Mỹ, Hàn Quốc, Khác và queue chỉ gồm bài phát được. Home cũng có cụm 12 bài dạng 3 cột như Zing, với lọc Tất cả/Việt Nam/Quốc tế và lối mở catalog đầy đủ; mỗi bài dùng cùng menu hành động chuẩn trên mobile, desktop và TV, đồng thời hỗ trợ chuột phải trên desktop.
- Khám phá Home có rail danh mục như Zing: Cho bạn, Thư giãn, Làm việc,
Trending, Ngủ ngon và Tập luyện; mỗi danh mục giữ Quick Play, banner và
collection rail riêng. Trong lúc chờ mạng, skeleton responsive giữ nguyên
nhịp Quick Play → banner → bài hát trên mobile, tablet, desktop và TV để nội
dung không bị nhảy khi tải xong; progress chuyển sang trạng thái tĩnh khi hệ
điều hành bật Reduce Motion. Trên tablet/desktop, thanh tìm kiếm nối thẳng vào rail
danh mục và Quick Play; rail danh mục được ghim ngay dưới toolbar khi cuộn,
còn tiêu đề lớn, lịch sử tìm kiếm và shortcut phụ không đẩy nội dung quan
trọng xuống dưới vùng đầu màn hình. Desktop rộng dùng sidebar nên không lặp
lại shortcut trong nội dung; tablet giữ shortcut sau cụm ưu tiên, còn
mobile/TV giữ thứ tự phù hợp thao tác chạm và remote. Rail Top 100 chính thức
có lối “TẤT CẢ” vào catalog đầy đủ. Quick Play được trình bày thành hero “Có thể bạn thích”
như Zing bằng card ngang thấp, artwork vuông bên trái và gradient coral–plum:
hai thẻ trên desktop/tablet, ba thẻ trên TV rộng và một thẻ có phần
xem trước trên mobile; nút trang nổi giữa mép card hỗ trợ chuột/bàn phím/remote.
Banner editorial nằm ngay sau đó dưới dạng một panorama thấp chiếm toàn bộ
bề rộng: ảnh chính thức được giữ nguyên, không phủ tiêu đề hay nút Play lên
creative; trên mobile vẫn hé card tiếp theo. Carousel banner tự chuyển khi rảnh như
Zing MP3, nhưng dừng ngay khi hover, focus hoặc đang vuốt và tắt hoàn toàn
khi hệ điều hành bật Reduce Motion. Mọi collection rail giữ thao tác vuốt trên
mobile, tự hiện nút lùi/tiến trên tablet, desktop và TV khi nội dung tràn, đồng
thời quay về đầu an toàn khi đổi danh mục. Rail “MV Nổi Bật” hiển thị video chính thức
đã kiểm tra, mở trang Zing trên
mobile/web/desktop và dùng QR handoff trên TV; app không relay hay tải file MV.
Card có action deck hover/focus kiểu Zing: thân card mở playlist/album detail,
Tim lưu/bỏ lưu Local-First, Play phát bài hợp lệ đầu tiên và menu Thêm cho
phép phát, mở thông tin, lưu hoặc chia sẻ liên kết chính thức; trên desktop,
chuột phải vào card mở đúng menu hành động này. Queue luôn chỉ gồm các bài
được phép phát theo đúng thứ tự. Trên các rail Discovery, Hub/Top 100 và
tab Album Mới Phát Hành, từng nghệ sĩ có định danh là link hover/focus riêng
mở hồ sơ nội bộ mà không kích hoạt card collection. Proxy
bỏ qua
adBannervà không tải mạng quảng cáo bên thứ ba. Cụm “Gợi Ý Bài Hát / Làm mới” ưu tiên catalog phát được từ Zing, hiển thị tối đa chín bài thành ma trận 3×3 trên desktop/TV và chỉ hiện action deck khi hover/focus; mobile luôn có menu Thêm để yêu thích, thêm queue/playlist, mở Thông tin, Song Radio hoặc chia sẻ; desktop mở đúng menu này bằng chuột phải và mọi menu đều có “Phát ngay” khi bài được phép phát. Metadata chính thức giữ từng nghệ sĩ thành link hover/focus mở hồ sơ ngay trong app mà không phát bài hay thay đổi queue. Khi dịch vụ không khả dụng, app tự chuyển sang chart hiện tại trên thiết bị. Cả hai luồng đều không gửi favorites, analytics hoặc lịch sử nghe lên proxy. Riêng rail “Nghe Gần Đây” lấy tối đa 10 bài đã nghe gần nhất từ bộ nhớ local, khử trùng lặp, mở đúng queue lịch sử và vẫn hoạt động khi Discovery trên mạng gặp lỗi. Từng card dùng chung menu Phát/Thông tin/Queue/Radio/Playlist/Chia sẻ/Tim/Mood; desktop hỗ trợ chuột phải và TV truy cập menu bằng focus/remote. Khối “BXH Nhạc Mới” trên Home làm nổi bật ba thứ hạng đầu, giữ trạng thái bài khóa và chỉ tạo queue theo đúng thứ tự từ các bài được phép phát; bài khóa vẫn có các thao tác metadata/thư viện an toàn nhưng không bao giờ hiện Phát, Queue hoặc Radio. - Chủ đề & Thể loại theo quốc gia, tâm trạng và hoạt động; Top 100 được chia thành các rail Nổi bật, Việt Nam, Châu Á, Âu Mỹ và Hòa Tấu như catalog Zing; tên nghệ sĩ trên playlist/album giữ nguyên điều hướng nội bộ như Zing MP3.
- Tablet và desktop dùng sidebar thích ứng theo nhịp điều hướng Zing MP3, gom Thư viện, Khám
phá, #zingchart, Phòng Nhạc LIVE, BXH Nhạc Mới, Chủ Đề & Thể Loại, Top 100 và
Dành cho bạn; Hub/Top 100 mở trực tiếp, cuối sidebar có Tạo playlist mới và
Danh sách phát. Nút Quay lại/Tiến lưu tối đa 50 trạng thái tab, tìm
kiếm, nghệ sĩ, album/playlist và phân khu Thư viện; desktop hỗ trợ
Alt+←/→. Trên Web, các đích điều hướng có ý nghĩa được đồng bộ với address bar và Browser History; Back/Forward khôi phục snapshot đang cache mà không tạo lại player, queue hay bài đang phát. Native và TV tiếp tục dùng stack nội bộ; webOS/Tizen không phụ thuộc History API. Trên tablet/desktop, toolbar Quay lại/Tiến, tìm kiếm và Cài đặt được ghim khi cuộn; riêng Discovery ghim thêm rail danh mục ngay bên dưới. Desktop rộng có avatar và thẻ Cá nhân local ngay trong sidebar, hiển thị số bài thích, playlist và phút nghe thật rồi mở thẳng dữ liệu tại máy, không giả lập tài khoản cloud. Sidebar thu gọn còn 70 px ở720–1133 px, hiển thị icon cùng tooltip nhưng vẫn giữ đủ mọi đích; từ1134 pxsidebar mở rộng có nhãn như Zing MP3. TV tiếp tục dùng rail ưu tiên remote. Điện thoại dùng bottom nav năm mụcThư viện · Khám phá · #zingchart · Radio · Cá nhân; tab Cá nhân gom hồ sơ local, bài thích, playlist, nghệ sĩ quan tâm, Daily/Mood Mix, thống kê và Wrapped mà không cần đăng nhập. BXH Nhạc Mới vẫn mở đầy đủ từ Khám phá thay vì chiếm thêm một mục điều hướng chính. - Tìm kiếm chính thức theo bài hát, nghệ sĩ, lời bài hát, playlist/album và MV,
có autocomplete kiểu
Zing với tối đa bốn từ khóa và sáu bài xem trước, hỗ trợ chuột, bàn phím và
remote TV. Chọn một bài xem trước sẽ tải đúng Song Detail theo public song ID,
không tự phát và chỉ hiện nút Play khi metadata xác nhận bài được phép phát;
spinner theo hàng và request guard ngăn kết quả cũ mở nhầm bài. Kết quả đầy
đủ có năm nhóm Tất cả/Bài hát/Playlist-Album/Nghệ sĩ/MV,
hàng Nổi bật, hồ sơ nghệ sĩ và trang
chi tiết playlist/album responsive ngay trong app. “Phát tất cả” dựng đúng
queue từ các bài có nguồn được phép; detail hiển thị số người yêu thích chính
thức, ngày phát hành, đơn vị cung cấp và thể loại. Sau track list là rail
“Nghệ Sĩ Tham Gia” với avatar tròn, theo dõi local và hồ sơ mở nội bộ, rồi
các rail “Xuất hiện trong”/“Có thể bạn quan tâm”; mỗi card liên quan dùng
chung action deck Play/Lưu/Thêm/Chia sẻ, menu chuột phải và điều hướng
bàn phím/TV. Từ 1200 px và khi vùng nội dung còn đủ rộng, trang
detail dùng workspace hai cột như Zing: artwork, tiêu đề, nghệ sĩ, ngày cập
nhật và hành động ở trái; lời tựa có Xem thêm/Rút gọn và track list ở phải.
Album dùng “Phát tất cả”, đánh số track và bỏ cột Album lặp lại; playlist dùng
“Phát ngẫu nhiên” cùng cột Album. Khi mở queue/lyrics, bảng tự chuyển compact
theo chiều rộng thực thay vì theo viewport nên không tràn.
Trên điện thoại, hero rút gọn để đưa track đầu vào ngay viewport, chỉ giữ nghệ
sĩ chính và bộ Play/Lưu/Thêm cỡ chạm; Chia sẻ nằm trong menu Thêm. Dưới 480 px,
mỗi track chỉ giữ một nút Thêm ở cuối hàng, còn Yêu thích vẫn có trong menu để
tiêu đề không bị bóp hẹp. Tablet cảm ứng dùng cùng hierarchy và chuyển dọc/ngang
theo vùng nội dung thực; TV giữ bố cục focus-friendly;
hồ sơ nghệ sĩ desktop từ 1180 px dùng hero tím tràn chiều ngang giống Zing OA,
với avatar tròn, tên lớn, nút Play tròn, số người quan tâm và hành động
Quan tâm/Chia sẻ. Ngay dưới hero, màn hình rộng ghép “Mới Phát Hành” với ba
“Bài Hát Nổi Bật” thành workspace hai cột như trang nghệ sĩ chính thức; khi
vùng nội dung hẹp do panel phát nhạc, hai cụm tự xếp dọc và ẩn metadata phụ để
không tràn. Mobile/tablet/TV vẫn giữ mật độ và touch/focus target phù hợp.
Các rail Single/EP, album và tuyển tập dùng chung Play/Lưu/Thêm/Chia sẻ,
right-click tương đương; desktop có mũi tên theo chiều rộng vùng nội dung,
mobile vuốt ngang, TV dùng D-pad/Enter. Hàng nghệ sĩ liên quan hỗ trợ Quan tâm
cục bộ ngay trên card.
Nghệ sĩ có định danh trở thành link hover/focus mở hồ sơ nội bộ và
album/playlist có thể lưu vào Thư viện local. Fallback cục bộ từ
#zingchart vẫn hoạt động khi proxy tìm kiếm gián đoạn. Trong lúc
chờ, skeleton giữ nguyên nhịp kết quả
Nổi bật → Playlisttrên mobile, tablet, desktop và TV; khi hệ thống bật Reduce Motion, thanh tiến trình chuyển sang trạng thái tĩnh. Tab Tất cả bám đúng thứ tự ZingNổi bật → Playlist nổi bật → 6 bài hát → Playlist/Album → MV → Nghệ sĩ/OA; cụm Nổi bật dùng ba card cùng chiều cao gồm một nghệ sĩ avatar tròn và hai bài hát cover vuông, chỉ giữ loại nội dung, tiêu đề, nghệ sĩ/số người quan tâm như Zing; album, thời lượng và action chi tiết nằm ở danh sách Bài hát bên dưới. Nút Tất cả tại từng nhóm chuyển sang danh sách đầy đủ. Nghệ sĩ/OA dùng lưới avatar tròn responsive 2/3/5 cột giống bề mặt tìm kiếm Zing, hỗ trợ hover/focus/remote TV và chỉ hiển thị số người quan tâm khi API chính thức cung cấp giá trị thật. Tab Bài hát dùng hàng compact kiểu Zing với cover 40 px, nghệ sĩ và thời lượng hai chữ số. Desktop rộng xếp lưới hai cột với Tim/Thêm luôn sẵn; bố cục một cột chỉ giữ metadata album khi vùng nội dung đủ rộng. Tab Playlist/Album dùng card ảnh vuông bo nhẹ, tiêu đề một dòng, nghệ sĩ tối đa hai dòng và lưới adaptive 2/3/4/5 cột; lớp Play kiểu Zing chỉ xuất hiện khi hover/focus nhưng toàn bộ card vẫn mở detail bằng chạm, click, Enter hoặc remote TV. Tab MV dùng thumbnail 16:9, thời lượng hai chữ số, avatar nghệ sĩ chính thức và metadata một dòng; overlay Play cũng chỉ hiện khi hover/focus rồi mở handoff Zing/QR đã kiểm tra. Bốn tab chuyên biệt dùng contract phân trang chính thức, mỗi trang tối đa 18 mục; mobile/tablet/desktop tự tải khi cuộn gần cuối, còn nút XEM THÊM vẫn là fallback truy cập được và là điều khiển chính trên TV. Kết quả cũ được giữ khi tải lỗi, loại trùng theo public ID. Nếu proxy chưa có credential ký, app giữ preview “Tất cả” và ẩn phân trang thay vì suy đoán. - Trang Thông Tin bài hát ngay trong Now Playing hiển thị metadata chính thức: nghệ sĩ, album, ngày phát hành, nhà phát hành, thể loại, nhạc sĩ, lượt nghe, lượt thích và bình luận. MV chỉ mở trang Zing đã kiểm tra hoặc dùng QR/copy trên TV và nền tảng không có launcher.
- Chia sẻ liên kết Zing MP3 chính thức cho bài hát, nghệ sĩ và playlist/album: mobile, web và desktop ưu tiên share sheet của hệ điều hành; TV hoặc adapter không hỗ trợ dùng QR + sao chép. Payload không chứa lịch sử nghe, favorites hay analytics cục bộ.
- Mở trực tiếp liên kết Zing MP3 trong app: dán URL vào thanh tìm kiếm để đi tới
bài hát, MV, nghệ sĩ, album/playlist, hub, Top 100, BXH tuần, BXH Nhạc Mới
hoặc Phòng Nhạc. Link bài hát mở trang thông tin và chờ người dùng bấm Play;
link
/video-clip/mở handoff xác nhận với nút Mở Zing MP3 hoặc QR trên TV. Cả hai đều không tự phát khi app được gọi từ bên ngoài. Android đăng ký HTTPS handoff ở mức best-effort; iOS, macOS, Windows, Linux và HarmonyOS dùng schemezingchart://open?url=...; Web nhận query?open=<URL đã encode>. Parser chỉ chấp nhận HTTPS Zing và ID/path đã biết, không chuyển tiếp URL tùy ý tới proxy. Route Mới Phát Hành giữ đủ tab Bài hát/Album và bộ lọcall/vpop/usuk/kpop/other, nên mở lạnh cũng như Back/Forward đều khôi phục đúng catalog đang xem. - Play, pause, stop, seek, previous/next, shuffle, repeat, âm lượng và mute. Header “Đang phát từ” giữ đúng nguồn queue như #zingChart, tìm kiếm, album, nghệ sĩ, BXH tuần, Mới Phát Hành, Thư viện, Song Radio hoặc Phòng Nhạc; ngữ cảnh này được giữ qua Next/Previous và khôi phục cùng phiên nghe local. Chất lượng stream có ba mức thật: Tự động ưu tiên 320 kbps rồi về 128 kbps, 128 kbps tiết kiệm dữ liệu và 320 kbps bắt buộc nguồn tương ứng. Bitrate được ký trong URL relay, lưu trên thiết bị và không làm lộ CDN hay mở tải offline. Nếu nguồn 320 lỗi, Now Playing cho phép thử lại hoặc chuyển sang Auto bằng một chạm mà vẫn giữ nguyên bài và hàng đợi.
- Seamless Next ở chế độ Tự động chỉ chuẩn bị đúng bài đầu tiên trong Tiếp theo khi bài hiện tại còn tối đa 30 giây. Khi bài phát hết, player chuyển sang deck đã chuẩn bị; nếu nền tảng hoặc nguồn không hỗ trợ, app tự dùng luồng phát tiêu chuẩn và không làm kẹt hàng đợi. Deck chờ chỉ buffer stream tạm thời; tính năng không lưu file audio/cache offline và không gửi queue hay lịch sử nghe lên proxy.
- Từ
720 pxtrở lên, tablet/desktop mặc định giữ nguyên catalog sau khi chọn bài và hiện playback dock ngang kiểu Zing MP3 phủ toàn bộ root shell bên dưới rail/sidebar lẫn nội dung. Dock có thông tin bài hát, transport, progress, volume và shortcut trực tiếp tới MV chính thức, Lời bài hát/Karaoke, Now Playing và “Danh sách phát”. Nút “Tùy chọn khác” cạnh tim mở nhanh Thông tin bài hát, Song Radio, thêm vào playlist và chia sẻ liên kết Zing chính thức. MV chỉ được tải metadata khi người dùng bấm và vẫn dùng luồng handoff Zing đã kiểm tra; desktop/tablet hẹp tự ẩn nhóm shortcut mở rộng để giữ transport dễ thao tác. Sidebar tablet dùng icon-only như Zing và drawer co giãn theo viewport để luôn chừa đủ không gian cho catalog. Drawer bên phải có ba tab Hàng đợi/Gần đây/Lời bài hát: queue cho phát, đổi thứ tự, xóa từng bài hoặc xóa toàn bộ phần chờ nhưng vẫn giữ bài hiện tại, progress và nguồn phát; thao tác xóa toàn bộ luôn có xác nhận an toàn trên mobile, desktop và TV. Lịch sử chỉ đọc dữ liệu local; lời tự bám câu đang hát, chạm để tua và có nút mở Karaoke toàn màn hình. Dock vẫn luôn hiện khi drawer mở. Drawer có nút đóng/Esc rõ ràng, còn tùy chọn Now Playing toàn màn hình vẫn được giữ. Dưới720 px, mobile dùng mini-player gọn và mở Now Playing toàn màn hình; TV giữ panel điều khiển 10-foot. - Mini-player mobile bám hierarchy của Zing: progress mảnh ở mép trên, artwork, tên bài/nghệ sĩ, Play/Pause và Next trong thanh 76 px ngay trên navigation 5 tab. Stop vẫn nằm trong Now Playing đầy đủ để tránh nút phá hủy phát nhạc ở bề mặt mini thường xuyên chạm.
- Nút Cài đặt trên header mở bottom sheet ở điện thoại hoặc dialog trên tablet/desktop/TV, gom Theme, shuffle, Smart Shuffle, repeat, Seamless Next Tự động/Tắt, Song Radio autoplay, sleep timer, tùy chọn desktop luôn mở Now Playing toàn màn hình, chất lượng Auto/128/320 kbps và thống kê Local-First. Mọi lựa chọn đều nối vào controller thật và được lưu trên thiết bị; không có tùy chọn giả.
- Now Playing mobile dùng hierarchy gần Zing MP3 hơn: artwork và metadata là tâm điểm, badge chất lượng Auto/128/320 kbps mở thẳng bộ chọn, transport nằm riêng, còn Lời bài hát/Hàng đợi/Song Radio/Hẹn giờ nằm trong action dock cố định. Thông tin bài hát, Smart Shuffle và Chế độ lái xe được giữ ở nhóm tiện ích gọn; app không gắn nhãn Lossless khi nguồn hiện tại chỉ hỗ trợ tối đa 320 kbps.
- Chế độ lái xe có thể bật từ Cài đặt hoặc Now Playing, giữ ảnh bìa, tiến trình và Previous/Play/Next/Stop bằng các nút lớn trong một giao diện ít thao tác; trạng thái được lưu trên máy. Đây là bề mặt giảm xao nhãng trong app, chưa tuyên bố tích hợp Android Auto hoặc Apple CarPlay.
- Now Playing mobile/desktop và collection detail dùng chính artwork đã tải làm lớp nền blur chuyển cảnh; scrim giữ độ tương phản và tự rơi về gradient local khi ảnh lỗi, không tạo thêm request API hay gửi dữ liệu cá nhân.
- Launcher, PWA, desktop, watch và TV dùng chung mark
# + nhịp sóngnguyên bản theo palette ink/coral/lime. Android có adaptive + monochrome icon; asset Apple là PNG RGB không alpha và mọi kích thước được sinh lại bằngnode tool/generate_brand_assets.mjs. - Queue kéo thả, vuốt sang phải để thêm bài và sleep timer.
- Shuffle dùng một thứ tự Fisher–Yates cho cả chu kỳ nên không lặp bài trước khi nghe hết queue; Previous/Next đi theo đúng lịch sử đã phát, Repeat All tạo chu kỳ mới không lặp ngay bài ở ranh giới. Thẻ TIẾP THEO trên mobile, desktop và TV luôn hiện bài thật sự sẽ phát sau Smart Shuffle, Song Radio hoặc thao tác Thêm vào hàng đợi. Thứ tự và con trỏ được lưu local để mở lại app vẫn tiếp tục đúng phiên.
- Danh sách Tiếp theo tách bài đang phát khỏi phần chờ và cho đổi đúng thứ tự phát thực tế, kể cả khi Shuffle/Repeat All đang bật. Mobile và desktop hỗ trợ kéo thả; TV có nút Lên/Xuống/Xóa dùng được bằng D-pad. System media cũng nhận chính timeline này, nên nút Next trên app, màn hình khóa và remote luôn thống nhất. Mọi chỉnh sửa được lưu local và giữ nguyên sau khi mở lại app.
- Smart Shuffle xen tối đa 10 gợi ý vào hàng đợi từ catalog hiện tại, xếp
hạng bằng likes/analytics local và đánh dấu
SMARTcho từng bài tự thêm. Tính năng không gửi gu nghe nhạc, favorites hoặc lịch sử lên proxy. - Song Radio lấy tối đa 30 bài tương tự từ catalog được phép; có thể bắt đầu từ menu bài hát/Now Playing và tự nối hàng đợi khi phát tới cuối.
- Phòng Nhạc LIVE hiển thị các kênh V-Pop, Bolero, US-UK, K-Pop và chương trình đang phát; HLS được relay/rewrite hoàn toàn qua proxy, không lộ URL CDN.
- Màn hình Lời bài hát/Karaoke toàn màn hình theo phong cách Zing, đồng bộ từng từ khi upstream có word timestamp, tự cuộn theo dòng và cho phép chạm một câu để tua; tự rơi về đồng bộ theo dòng hoặc lời tĩnh khi cần.
- Lyric Card cho chọn tối đa bốn câu, xem trước rồi xuất PNG qua share/download/ save phù hợp nền tảng; TV dùng QR local. Ảnh được render tại máy, không tải artwork và không gửi đoạn lời, lịch sử hay analytics lên proxy.
- Background playback cùng system media controls trên nền tảng được hỗ trợ.
- Thư viện Local-First có thanh phân mục kiểu Zing cho Tổng quan, Bài hát, Gần đây, Playlist, Album và Nghệ sĩ; yêu thích, nghệ sĩ/OA đã quan tâm, album/playlist Zing đã lưu, playlist cá nhân, lịch sử nghe, tìm kiếm gần đây, analytics 7/30 ngày/theo năm, Daily Mix và Mood Mix Chill/Gym/Tập trung đều nằm trên thiết bị và không cần tài khoản.
- Playlist cá nhân có workspace riêng với cover mosaic, Phát/Trộn bài, đổi tên, xóa, kéo thả sắp xếp trên mobile/desktop, nút Lên/Xuống trên TV và xóa bài có Hoàn tác đúng vị trí. Picker luôn cho tạo playlist mới rồi thêm bài ngay mà không rời màn hình đang duyệt; chỉnh playlist không thay đổi queue đang phát.
- Lịch sử nghe có workspace Local-First riêng, nhóm theo ngày địa phương, hiển thị thời điểm và thời lượng đã nghe, Phát/Trộn bài, menu bài hát chuẩn và focus remote TV. Xóa lịch sử/thống kê luôn xác nhận trước, không xóa favorites, playlist hoặc mood tag.
- Mini Wrapped 6 slide quanh năm; xuất PNG trên phone/web/desktop và QR tóm tắt local trên TV.
- Export/import backup JSON v3 theo hai chế độ Merge hoặc Overwrite; vẫn đọc được backup v1/v2.
- Theme Sáng/Tối/Theo hệ thống, giữ nhận diện charcoal, coral và lime.
- UI adaptive cho mobile, tablet, desktop và giao diện 10-foot cho TV: dưới
720 pxdùng mini-player/full Now Playing, từ720 pxgiữ catalog cùng dock toàn chiều rộng. - Catalog dùng kênh cập nhật riêng: nhịp position/duration/volume chỉ dựng lại player, không dựng lại toàn bộ Home, Discovery hay danh sách BXH; favorites, queue và thư viện vẫn phản hồi ngay trên mọi kích thước màn hình.
- Now Playing widget trên Android, iOS/iPadOS 17+, macOS 14+ và HarmonyOS; companion remote trên Wear OS 3+ và watchOS 10+.
- Trong app: bấm biểu tượng mắt xích trong ô tìm kiếm để dán URL, hoặc dán URL trực tiếp rồi nhấn Enter/Search.
- Các URL tìm kiếm chính thức
/tim-kiem/tat-ca,/tim-kiem/bai-hat,/tim-kiem/playlist,/tim-kiem/artistvà/tim-kiem/video(kèm đúng một tham sốq) mở thẳng query và tab tương ứng mà không khởi động lại player. - Link MV
https://zingmp3.vn/video-clip/.../<id>.htmlluôn chờ thao tác MỞ ZING MP3; TV chỉ hiện QR/copy để tránh vòng lặp launcher. - Scheme đa nền tảng:
zingchart://open?url=https%3A%2F%2Fzingmp3.vn%2Ftop100. - Web/PWA:
https://<client-host>/?open=https%3A%2F%2Fzingmp3.vn%2Ftop100. - Web thường dùng
PathUrlStrategyvới<base href>đã cấu hình. Muốn cold-start trực tiếp bằng đường dẫn như/new-release/album, host phải rewrite đường dẫn đó vềindex.html. - Đích Zing chính thức nằm trong tham số
openđược chuẩn hóa về hosthttps://zingmp3.vn, bỏ fragment/tracking và giữ đúng subtype như/new-release/songhoặc/new-release/album; thanh địa chỉ vẫn dùng host của client. Khám phá, Hub local, Thư viện và Dành cho bạn lần lượt dùng?view=discovery,?view=hubs,?view=libraryvà?view=for-you. Trang chi tiết mix dùng thêmmix=daily|chill|gym|focus; Thư viện có thể giữsectionvà ID playlist local. URL không chứa tên playlist, ID bài hát hay dữ liệu nghe. - Chỉ thao tác điều hướng ngữ nghĩa đã commit mới thêm history entry. Các kết quả tạm thời khi gõ tìm kiếm được gộp bằng replace trong cùng một entry; tải thêm trang, scroll, seek và thay đổi queue không làm đầy Browser History.
- Handoff HTTPS trên Android là best-effort: một số máy/phiên bản cũ có thể hiện app trong chooser, còn Android 12+ thường mở domain chưa xác minh bằng browser. Đường ổn định là scheme hoặc nút dán link. Do domain thuộc Zing MP3, app không tuyên bố Android App Link hay Apple Universal Link đã xác minh.
Chưa hỗ trợ tải/caching file nhạc để nghe offline. PWA chỉ cache app shell và dữ liệu không phải audio.
- Thời gian nghe được cộng từ tiến trình phát thực tế; bước nhảy do seek không
được tính. Một lượt hợp lệ khi đạt
min(30 giây, 50% thời lượng). - Chỉ Next, Previous hoặc chọn bài khác trước ngưỡng mới là early skip. Pause, Stop và seek là tín hiệu trung tính; completion được ghi khi player phát hết.
- Dữ liệu giữ tối đa 500 lịch sử gần nhất, chi tiết theo bài trong 62 ngày và tổng hợp tháng trong 24 tháng. Tất cả nằm trên thiết bị và không gửi lên proxy.
- Daily Mix lấy ứng viên từ chart, favorites, playlist và lịch sử, tối đa 25 bài và không quá hai bài cùng nghệ sĩ. Cold start ưu tiên bài đã thích rồi tới thứ hạng chart.
- Mood không được suy đoán từ tên bài. Người dùng tự gắn nhiều nhãn Chill, Gym hoặc Tập trung từ menu bài hát và màn hình Now Playing.
- Backup v3 chứa analytics, mood, nghệ sĩ đã quan tâm và album/playlist đã lưu. Merge dùng installation/date/song cùng bộ đếm lớn nhất để import lặp lại không cộng trùng; Overwrite vẫn giữ installation ID đang hoạt động. Giới hạn file là 5 MB.
- “Xóa lịch sử và thống kê” không xóa favorites, playlist hoặc mood tags.
Wrapped dùng Canvas nội bộ để dựng gradient, typography và họa tiết, không tải ảnh bìa khi xuất nên không phụ thuộc CORS. Android/iOS mở share sheet, Web tải hoặc chia sẻ PNG, desktop chọn nơi lưu; TV hiển thị QR chứa summary đã phiên bản hóa và không cần server. HarmonyOS tự rơi về summary/QR có thể sao chép nếu adapter share/save không khả dụng.
- Hai audio deck được quản lý sau cùng một interface: chỉ deck đang hoạt động phát event tới UI; deck chờ được chuẩn bị im lặng và chỉ được đưa lên khi bài hiện tại hoàn tất tự nhiên.
- Đích preload gắn với bài hiện tại, đúng occurrence đầu tiên của True Up Next, revision hàng đợi và chất lượng stream. Reorder, chọn bài thủ công, đổi repeat, đổi chất lượng, Stop, LIVE hoặc sleep-after-current đều hủy preload cũ.
- Manual Next/Previous vẫn được ghi là early skip đúng quy tắc analytics; chuyển tự nhiên chỉ ghi completion một lần. Lỗi preload luôn rơi về resolve/play bình thường.
- Preference được lưu local trong player snapshot v12. Đây là Seamless Next có fallback, chưa tuyên bố gapless/crossfade cho tới khi vượt capability test trên toàn bộ thiết bị thật.
- Chạm vào thân card Daily Mix, Chill, Gym hoặc Tập trung sẽ mở trang chi tiết; nút Play trên card vẫn phát ngay mà không đổi màn hình.
- Workspace dùng bố cục playlist kiểu Zing với cover mosaic, mô tả cold start, Play/Shuffle và danh sách bài thích ứng cho điện thoại, tablet, desktop và TV.
- Mỗi bài có Play, Queue, Like, Mood, Playlist, Radio, Share và Thông tin qua menu chuẩn; chọn một bài tạo hàng đợi đúng snapshot mix đang xem. Play trên card luôn bắt đầu đúng thứ tự mix, đặt đúng nguồn Daily/Mood và tắt Shuffle cũ.
- Tín hiệu local của bài bị khóa vẫn có thể giữ cho Like/Mood/metadata, nhưng bị loại khỏi Mix phát được; Play, Queue và Radio luôn fail-closed kể cả khi import snapshot cũ chưa có trường quyền phát.
- Back/Forward và liên kết Web khôi phục đúng mix bằng route local-safe
?view=for-you&mix=.... Việc mở/duyệt mix không gọi API recommendation và không gửi favorites, mood hoặc analytics lên mạng.
- Hồ sơ Nghệ sĩ/OA vẫn mở nhanh với 50 bài đầu tiên cùng metadata phân trang
gọn; trang
/{alias}/bai-hatsau đó có thể duyệt toàn bộ catalog được phép quaGET /v1/artists/{id}/songs?page={page}&limit={limit}. - Điện thoại, tablet và desktop tự tải khi gần cuối danh sách nhưng luôn giữ nút XEM THÊM dễ truy cập làm fallback. TV chỉ tải khi người dùng bấm nút này bằng remote và khôi phục focus sau mỗi lần tải hoặc thử lại.
- Lỗi trang chỉ hiện tại footer: các bài đã tải vẫn được giữ và có thể thử lại. Client khử trùng lặp theo ID, bỏ response trễ sau khi đổi nghệ sĩ/route và không tạo thêm Browser History khi tải trang. Nếu một trang không bổ sung bài hợp lệ, tự tải sẽ dừng để tránh lặp request nhưng nút XEM THÊM vẫn cho phép người dùng tiếp tục thủ công; trạng thái dừng hoặc adapter không hỗ trợ được giữ nguyên qua Back/Forward và khi mở rồi quay lại từ album.
- Quyền phát được kiểm tra fail-closed đồng thời ở mức hồ sơ, trang và từng bài. Bài bị khóa vẫn hiện metadata nhưng không có Play, Queue hoặc Radio.
- Request chỉ chứa artist ID, page và limit. Favorites, mood, lịch sử nghe và analytics tiếp tục nằm hoàn toàn trên thiết bị, không được gửi lên proxy.
- Hồ sơ Nghệ sĩ/OA có thanh điều hướng thống nhất Tổng quan · Bài hát ·
Single & EP · Album · MV. Route chính thức
/{alias}/albumđược parse fail-closed, canonicalize và khôi phục đúng qua Back/Forward. - Single/EP, Album và MV mở thành grid catalog đầy đủ thay vì rail ngang: 2 cột trên điện thoại, 3 cột trên tablet, 4–5 cột trên desktop và TV. Card giữ nguyên Play/Lưu/Thêm/Chia sẻ, bàn phím và remote focus của catalog Zing.
- Nội dung được khử trùng lặp theo public ID nhưng giữ nguyên thứ tự upstream. Chỉ section có nhãn Single/EP hoặc Album rõ ràng mới được phân loại; section mơ hồ tiếp tục nằm ở Tổng quan để không gắn nhãn sai.
- Số lượng được ghi rõ là nội dung đã tải, không tuyên bố toàn bộ catalog khi payload nghệ sĩ đang bị giới hạn. Deep link tới section trống vẫn giữ tab và hiện empty state đúng loại, không âm thầm quay về Tổng quan.
- Chuyển tab dùng lại artist detail đã cache, không tự phát nhạc và không tải lại artist detail. Riêng Bài hát có thể tải trang catalog giới hạn khi cần; favorites, lịch sử và analytics vẫn không được gửi lên mạng.
- Cuối trang Tổng quan có khối Về {tên nghệ sĩ} theo bố cục biên tập của Zing MP3: ảnh cover và nội dung đặt cạnh nhau trên màn hình rộng, tự chuyển thành một cột gọn trên điện thoại hoặc tablet có chiều rộng hẹp.
- Phần xem trước đo overflow theo đúng chiều rộng, cỡ chữ và text scale hiện tại. Nút XEM THÊM chỉ xuất hiện khi tiểu sử thật sự bị rút gọn; modal sau đó hiển thị toàn bộ nội dung dưới dạng văn bản có thể chọn/sao chép.
- Số người quan tâm, số thành tích, tên thật, quốc gia và ngày sinh chỉ được hiển thị khi artist detail có dữ liệu tương ứng; ứng dụng không suy đoán hoặc tự tạo metadata còn thiếu.
- Ảnh giới thiệu ưu tiên cover → avatar → placeholder cục bộ mang chữ cái đầu tên nghệ sĩ. Lỗi tải ảnh cũng rơi về placeholder nên bố cục vẫn ổn định khi mạng yếu hoặc ảnh upstream không còn khả dụng.
- Mobile, tablet, desktop và TV dùng chung nội dung nhưng có spacing, typography
và vùng focus thích ứng. Modal đóng được bằng nút Back/remote Back hoặc
Escape; nút đóng và XEM THÊM giữ touch/focus target phù hợp từng thiết bị. - Tính năng dùng lại artist detail đã cache và không thêm API/endpoint proxy hoặc request catalog mới; favorites, lịch sử và analytics vẫn nằm trên thiết bị.
Các ảnh dưới đây được render từ UI hiện tại bằng dữ liệu demo hoàn toàn cục bộ, sau đó nhóm theo mốc tính năng. Chúng không phải ảnh lưu lại từ binary lịch sử và không chứa dữ liệu người dùng thật.
![]() Dành cho bạn · Daily Mix và Mood Mix tại máy |
![]() Thống kê · 7 ngày, 30 ngày và theo năm |
![]() Mini Wrapped · sáu slide và xuất PNG |
![]() TV 10-foot UI · điều hướng remote, mix local và player panel |
||
![]() Seamless Next có fallback · chỉ buffer tạm đúng bài đầu tiên của Tiếp theo trong 30 giây cuối, không lưu file audio/cache offline |
![]() Local Mix Workspace · mở card để duyệt trước, Play/Shuffle riêng, thao tác đầy đủ cho từng bài và route local-safe không lộ dữ liệu nghe |
![]() Artist Catalog Pagination · mở tức thì với 50 bài đầu, tự tải gần cuối trên thiết bị cảm ứng/desktop, giữ XEM THÊM cho fallback và remote TV |
![]() Artist Discography Tabs · điều hướng media thống nhất, Album grid responsive, action kiểu Zing và Back/Forward dùng lại detail đã cache |
![]() Desktop/TV · bố cục biên tập hai cột, thống kê người quan tâm/thành tích và metadata chính thức |
![]() Mobile/tablet · một cột gọn, preview nhận biết overflow và modal tiểu sử đầy đủ có thể chọn |
![]() Tablet 768 px · sidebar 70 px vẫn mở trực tiếp đủ catalog, queue dùng chung workspace và dock chạy xuyên suốt bên dưới như Zing MP3 |
Hai ảnh v1.3e được render bằng web renderer từ fixture artist-about; fixture
dùng để tái tạo toàn bộ gallery nằm tại
tool/docs_screenshot_app.dart. Entry point này
không gọi proxy, audio thật hoặc media service của hệ điều hành.
Icon đa nền tảng được sinh từ
assets/brand/zingchart-mark.svg; chạy
node tool/generate_brand_assets.mjs --check để phát hiện asset cũ hoặc thiếu.
| Bề mặt | Trạng thái | Điều khiển |
|---|---|---|
| Android Home Widget | Có | Previous, play/pause, next |
| Fire OS tablet | Có trong APK Android; phụ thuộc launcher của thiết bị có cho đặt widget hay không | Previous, play/pause, next |
| iOS/iPadOS WidgetKit | iOS/iPadOS 17+ | Previous, play/pause, next qua AudioPlaybackIntent |
| macOS WidgetKit | macOS 14+ | Previous, play/pause, next |
| HarmonyOS Service Widget | API 18 | Previous, play/pause, next; mở EntryAbility khi cần đánh thức Flutter |
| Wear OS remote | Wear OS 3+, ghép với Android phone | Previous, play/pause, next qua Data Layer |
| watchOS remote | watchOS 10+, ghép với iPhone | Previous, play/pause, next qua WatchConnectivity |
| Windows/Linux/Web/TV | Không có home-widget portable trong v1 | Dùng SMTC, MPRIS, Media Session hoặc remote TV sẵn có |
Widget/watch chỉ nhận snapshot metadata, trạng thái và lệnh điều khiển. Lịch sử, analytics, favorites và URL stream không được gửi ra server hay sang wearable.
Flutter clients
│
├── GET /v1/chart
├── GET /v1/charts/new-releases
├── GET /v1/charts/weekly?region={region}&week={week}&year={year}
├── GET /v1/discovery/categories
├── GET /v1/discovery/recommendations
├── GET /v1/discovery/home?categoryId={id}
├── GET /v1/search/suggestions?q={query}
├── GET /v1/hubs
├── GET /v1/hubs/{id}
├── GET /v1/top-100
├── GET /v1/releases
├── GET /v1/artists/{alias}
├── GET /v1/artists/{id}/songs?page={page}&limit={limit}
├── GET /v1/search?q={query}
├── GET /v1/collections/{id}
├── GET /v1/songs/{code}/lyrics
├── GET /v1/songs/{code}/radio
├── GET /v1/radio
├── GET /v1/radio/{id}/source
├── GET /v1/live-streams/{opaqueToken}
├── GET /v1/songs/{code}/source
└── GET /v1/streams/{signedToken}
│
▼
Node/Fastify proxy
│
▼
Zing upstream
| Thành phần | Vị trí | Vai trò |
|---|---|---|
| Flutter app | lib/ |
UI, playback, Local-First library |
| Proxy | proxy/ |
Chuẩn hóa chart, ký URL và relay audio |
| Native runners | android/, ios/, web/, windows/, macos/, linux/ |
Runner từng hệ điều hành |
| Companion surfaces | android/wear/, ios/ZingChartWatch/, ios/ZingChartWidget/, macos/ZingChartWidget/ |
Widget và smartwatch remote |
| Packaging | packaging/ |
Fire OS, TV, HarmonyOS, Apple target preparation và installer desktop |
| CI/Release | .github/workflows/ |
Test và build artifact đa nền tảng |
GET /v1/chart trả cả danh sách 100 bài và trend 24 giờ của top 3. Flutter sử
dụng trực tiếp các điểm realtime này cho biểu đồ #zingchart; không mô phỏng
counter ở phía client và không gửi dữ liệu nghe local lên proxy. UI dựng top 10
trước, chỉ dựng đủ top 100 khi người dùng yêu cầu, nhưng queue phát luôn đầy đủ.
GET /v1/charts/new-releases dùng current-API adapter được cấp quyền, cache
ngắn hạn và chỉ đánh dấu playable khi upstream trả streamingStatus = 1.
Endpoint này cần cặp ZING_CURRENT_API_KEY/ZING_CURRENT_API_SIGNING_KEY; các
credential chỉ tồn tại trên proxy.
GET /v1/charts/weekly chuẩn hóa Bảng Xếp Hạng Tuần chính thức cho vietnam,
usuk hoặc korea. week và year phải xuất hiện cùng nhau; nếu bỏ cả hai,
upstream trả tuần mới nhất. Proxy ký request ở server, cache single-flight theo
khu vực/kỳ và chỉ bật playback khi streamingStatus = 1.
GET /v1/songs/{code}/lyrics ký request lời bài hát ở proxy, chuẩn hóa karaoke
thành các dòng có startTimeMs/endTimeMs và trả fallback lời tĩnh khi không
có timestamp. Flutter không gọi URL file lời bên ngoài; cache và single-flight
được khóa theo mã bài hát, còn credential luôn ở server.
GET /v1/songs/{code}/radio ký request recommendation ở proxy và chỉ giữ bài
có streamingStatus = 1, không private/pre-release, không trùng seed hoặc trùng
ID. Kết quả tối đa 30 bài được cache single-flight ngắn hạn; favorites, analytics
và lịch sử nghe local tuyệt đối không được gửi lên endpoint này.
GET /v1/radio trả danh sách Phòng Nhạc LIVE đã chuẩn hóa. Endpoint source chỉ
trả token first-party được mã hóa; master/media playlist, key và segment HLS
được proxy kiểm tra allowlist, rewrite thành /v1/live-streams/{opaqueToken} và
relay với timeout/body cap. Client không nhận URL CDN, credential hoặc payload
radio thô; phiên LIVE cũng không được ghi vào analytics, lịch sử hay backup.
GET /v1/discovery/categories chuẩn hóa rail danh mục Home; client tự thêm
“Cho bạn” với ID -1. GET /v1/discovery/home?categoryId={id} trả Quick Play,
banner editorial và collection rail đúng danh mục đã chọn; adBanner quảng cáo
bị loại bỏ. Flutter chỉ gọi proxy; khi mở một card, app dùng tiếp endpoint
collection detail hiện có. Category list và từng Home
được single-flight cache theo SEARCH_CACHE_TTL_MS; không endpoint nào nhận
analytics hoặc lịch sử nghe local.
Rail “Nghe Gần Đây” là dữ liệu Local-First do Flutter dựng trực tiếp từ lịch sử trên thiết bị; proxy không có endpoint, tham số hoặc payload nào cho rail này. Xóa lịch sử trong app cũng xóa nội dung rail nhưng không ảnh hưởng favorites. Menu hành động trên rail dùng lại đúng contract của các hàng bài hát khác và không gửi lịch sử local qua mạng.
GET /v1/discovery/recommendations ký request Song Station trên proxy, chỉ giữ
tối đa 12 bài công khai có streamingStatus = 1 và trả metadata đã chuẩn hóa.
Client luân phiên sáu bài mỗi lần bấm “Làm mới”; nếu endpoint lỗi, UI dùng chart
hiện tại làm fallback fail-closed. Request này không chứa installation ID,
favorites hay lịch sử.
GET /v1/hubs chuẩn hóa trang Chủ đề & Thể loại thành bốn nhóm Nổi bật, Quốc
gia, Tâm trạng/Hoạt động và Thể loại. GET /v1/hubs/{id} trả metadata cùng các
playlist rail của một hub; GET /v1/top-100 trả các nhóm Top 100 theo đúng thứ
tự upstream. Ba endpoint dùng current-API adapter được cấp quyền, validation
fail-closed, cache single-flight và không nhận bất kỳ dữ liệu Local-First nào.
GET /v1/releases gom hai catalog Bài hát/Album Mới Phát Hành, chuẩn hóa khu
vực Việt Nam, Âu Mỹ, Hàn Quốc và Khác, đồng thời chỉ đánh dấu bài phát được khi
streamingStatus đúng bằng 1. Endpoint cache single-flight ngắn hạn và không
nhận lịch sử nghe hay dữ liệu cá nhân từ client. Discovery Home tái sử dụng
snapshot này để dựng cụm 12 bài theo bố cục ba cột của Zing; lọc “Quốc tế” chỉ
gộp các vùng ngoài Việt Nam và queue luôn loại bài bị khóa.
GET /v1/artists/{alias} trả hồ sơ Nghệ sĩ/OA chính thức gồm metadata, người
quan tâm, 6 bài nổi bật, 50 bài đầu cùng metadata phân trang gọn, tối đa 50 MV
công khai cho trang “Tất cả”, Single/EP, album, tuyển tập, nghệ sĩ liên quan và
tiểu sử plain text. App nhận trực tiếp các URL nghệ sĩ chính thức
/{alias}/bai-hat, /{alias}/single và /{alias}/video; trang tổng quan có
nút “TẤT CẢ” cho từng nhóm. GET /v1/artists/{id}/songs?page={page}&limit={limit}
đọc tiếp toàn bộ catalog bài hát được phép theo artist ID, cache/single-flight
theo ID/trang/limit và trả tổng số cùng cờ hasMore. Client giữ 50 bài đầu nếu
phân trang lỗi, cho thử lại, khử trùng lặp và bỏ response trễ. Nếu catalog đầy
đủ lỗi, proxy vẫn giữ cụm bài nổi bật làm fallback. Proxy giới hạn kích thước
từng nhóm, bỏ mục lỗi và chỉ bật bài khi các gate hồ sơ, trang và từng mục đều
cho phép; bài khóa vẫn thấy metadata nhưng Play, Queue và Radio fail-closed.
Hai endpoint không nhận favorites, mood, lịch sử hoặc analytics; client không
gọi trực tiếp API Zing hay nhận credential ký request.
GET /v1/search/suggestions trả tối đa bốn từ khóa và sáu bài xem trước từ
adapter được ký tại proxy, hoặc fallback từ tìm kiếm legacy khi chưa cấu hình
credential. Endpoint không suy đoán quyền phát; chọn gợi ý luôn chạy lại
GET /v1/search với kiểm tra quyền fail-closed. Khi có credential current API,
proxy ký tìm kiếm chính thức rồi chuẩn hóa bài hát (kèm cờ có lời), nghệ sĩ/OA,
playlist/album và MV; bài chỉ phát khi streamingStatus = 1. MV không được relay
hay tải về: app chỉ mở trang zingmp3.vn/video-clip/ đã kiểm tra, còn TV hoặc
nền tảng thiếu adapter sẽ hiện QR/copy. Khi chưa có credential, fallback legacy
không suy đoán quyền phát và không trả MV. GET /v1/collections/{id}
đọc metadata công khai cùng track list đã chuẩn
hóa; bài trùng với chart dùng luôn mã legacy đang phát được. Các bài ngoài chart
chỉ được bật Play khi proxy có current-API adapter được cấp quyền. Credential
của adapter chỉ nằm trong biến môi trường proxy, tuyệt đối không đóng gói vào
Flutter.
Thêm type=songs|artists|collections|videos&page=1&limit=18 để lấy trang typed
chính thức; proxy cache/single-flight theo đầy đủ query/type/page/limit, chỉ nâng
mã phát từ chart cho trang bài hát và trả SEARCH_PAGINATION_UNAVAILABLE khi
adapter ký chưa được cấu hình. Client giữ kết quả aggregate lúc đó và không gửi
lịch sử nghe, favorites hay analytics trong request tìm kiếm.
- Git.
- FVM và Flutter
3.44.7. - Dart đi kèm Flutter; project yêu cầu Dart
>=3.12.0 <4.0.0. - Node.js
22+cho proxy. Docker có thể thay thế Node khi chỉ chạy proxy. - Một proxy URL; release build bắt buộc dùng HTTPS.
| Nền tảng | Toolchain bổ sung |
|---|---|
| Android/Android TV/Fire OS/Wear OS | Android SDK 36, Android Studio hoặc command-line tools, JDK 17; Wear OS emulator/device cho E2E |
| iOS/macOS/watchOS | macOS, full Xcode, CocoaPods; Ruby gem xcodeproj 1.27.0; WidgetKit yêu cầu iOS 17+/macOS 14+, watchOS 10+ |
| Windows | Windows, Visual Studio 2022 với Desktop development with C++, Windows 10/11 SDK |
| Linux | Clang, CMake, Ninja, GTK 3, LZMA và GStreamer development packages |
| webOS TV | Node.js và @webos-tools/cli@3.2.5 |
| Tizen TV | Tizen Studio, TV Extension, Web CLI và Samsung certificate profile |
| HarmonyOS | CPF-Flutter OHOS, DevEco Studio CLI và HarmonyOS SDK 5.1.0 API 18 |
git clone https://github.com/LamPPKK/Zing-Chart.git
cd Zing-Chart
fvm install 3.44.7
fvm use 3.44.7
fvm flutter doctor -vfvm flutter pub getChỉ chạy code generation khi thay đổi DTO/Retrofit hoặc file có annotation:
fvm dart run build_runner build --delete-conflicting-outputscd proxy
cp .env.example .env
set -a
. ./.env
set +a
npm ci
npm run devNode không tự đọc file .env; ba lệnh set -a, . ./.env, set +a nạp và
export cấu hình vào process hiện tại. Khi đổi file .env, hãy khởi động lại
proxy.
Kiểm tra proxy trong terminal khác:
curl http://localhost:8080/health
curl http://localhost:8080/v1/chart
curl http://localhost:8080/v1/charts/new-releases
curl 'http://localhost:8080/v1/charts/weekly?region=vietnam'
curl 'http://localhost:8080/v1/charts/weekly?region=usuk&week=33&year=2026'
curl http://localhost:8080/v1/discovery/categories
curl http://localhost:8080/v1/discovery/recommendations
curl 'http://localhost:8080/v1/discovery/home?categoryId=-1'
curl 'http://localhost:8080/v1/discovery/home?categoryId=14'
curl http://localhost:8080/v1/hubs
curl http://localhost:8080/v1/hubs/IWZ9Z09B
curl http://localhost:8080/v1/top-100
curl http://localhost:8080/v1/releases
curl http://localhost:8080/v1/artists/Son-Tung-M-TP
curl 'http://localhost:8080/v1/artists/IWZ9Z017/songs?page=2&limit=50'
curl --get http://localhost:8080/v1/search/suggestions --data-urlencode 'q=Sơn Tùng M-TP'
curl --get http://localhost:8080/v1/search --data-urlencode 'q=Sơn Tùng M-TP'
curl --get http://localhost:8080/v1/search --data-urlencode 'q=Sơn Tùng M-TP' \
--data 'type=songs&page=1&limit=18'
curl http://localhost:8080/v1/collections/6DIZIU79
curl http://localhost:8080/v1/songs/ZW79ZBE8/detail
curl http://localhost:8080/v1/songs/Z9WE0E96/lyrics
curl http://localhost:8080/v1/songs/Z9WE0E96/radio
curl http://localhost:8080/v1/radio
curl http://localhost:8080/v1/radio/IWZ979UB/sourceKết quả health hợp lệ:
{"status":"ok"}cd ..
fvm flutter devices
fvm flutter run -d <desktop-device-id> \
--dart-define=API_BASE_URL=http://localhost:8080Chọn thiết bị cụ thể bằng -d:
fvm flutter run -d chrome --web-port=3000 \
--dart-define=API_BASE_URL=http://localhost:8080
fvm flutter run -d <device-id> \
--dart-define=API_BASE_URL=https://your-dev-proxy.example.comlocalhost:8080 phù hợp cho desktop và Chrome chạy trên cùng máy; web dev dùng
port 3000 để khớp CORS mặc định. Android/iOS emulator hoặc thiết bị thật nên
dùng proxy HTTPS truy cập được từ thiết bị.
Các biến chính nằm trong proxy/.env.example:
| Biến | Ý nghĩa |
|---|---|
NODE_ENV |
development hoặc production |
HOST, PORT |
Địa chỉ listen của proxy |
CORS_ORIGINS |
Allowlist origin, phân cách bằng dấu phẩy |
PUBLIC_BASE_URL |
URL public của proxy; production bắt buộc HTTPS |
STREAM_TOKEN_SECRET |
Secret ký stream token, production tối thiểu 32 ký tự |
STREAM_TOKEN_TTL_SECONDS |
Thời gian sống stream token |
STREAM_HOSTS |
Allowlist CDN upstream |
UPSTREAM_TIMEOUT_MS |
Timeout upstream |
CHART_CACHE_TTL_MS |
TTL cache chart |
RATE_LIMIT_MAX, RATE_LIMIT_WINDOW_MS |
Giới hạn request |
TRUST_PROXY_HOPS |
Số reverse proxy tin cậy phía trước service |
cd proxy
npm ci
npm run typecheck
npm test
npm run build
cp .env.example .env.production
# Chỉ tạo file này lần đầu; sửa NODE_ENV=production, URL, CORS và secret.
set -a
. ./.env.production
set +a
npm startTạo proxy/.env.production với NODE_ENV=production, HTTPS public URL, CORS
allowlist và secret riêng. Sau đó chạy từ project root:
docker build -t zingchart-proxy:local ./proxy
docker run --rm \
--env-file proxy/.env.production \
-p 8080:8080 \
zingchart-proxy:localKiểm tra container:
curl https://your-proxy.example.com/healthKhông dùng https://api.example.invalid cho bản phát hành. URL này chỉ khiến
app hiển thị màn hình lỗi cấu hình an toàn.
Chạy từ project root:
fvm flutter pub get
fvm dart format --output=none --set-exit-if-changed lib test
fvm flutter analyze
fvm flutter test --reporter expandedKiểm tra proxy:
cd proxy
npm ci
npm run typecheck
npm test
npm run build
cd ..Kiểm tra packaging scripts:
node --test \
packaging/apple/*.test.mjs \
packaging/fireos/*.test.mjs \
packaging/harmonyos/*.test.mjs \
packaging/tv/*.test.mjs \
packaging/wearos/*.test.mjsCác ví dụ dưới đây dùng:
API_BASE_URL=https://proxy.example.com
VERSION=1.0.0Thay URL và version bằng giá trị thật trước khi build.
Build APK và Android App Bundle:
fvm flutter build apk --release \
--dart-define=API_BASE_URL="$API_BASE_URL"
fvm flutter build appbundle --release \
--dart-define=API_BASE_URL="$API_BASE_URL"Artifact:
build/app/outputs/flutter-apk/app-release.apkbuild/app/outputs/bundle/release/app-release.aab
Cài APK bằng ADB:
adb install -r build/app/outputs/flutter-apk/app-release.apkĐặt keystore tại android/app/release.jks, rồi tạo file
android/key.properties:
storeFile=release.jks
storePassword=YOUR_STORE_PASSWORD
keyAlias=YOUR_KEY_ALIAS
keyPassword=YOUR_KEY_PASSWORDKhông commit keystore, password hoặc key.properties. Nếu file này không tồn
tại, Gradle sẽ ký release APK bằng debug key; artifact đó chỉ dùng để test.
Home Widget được đóng ngay trong APK Android và dùng MediaSession của
audio_service; không khởi tạo player riêng. Sau khi cài app, nhấn giữ màn hình
chính → Widgets → #zingChart.
Build APK remote cho Wear OS sau khi Flutter đã tạo Android build config:
fvm flutter build apk --release \
--dart-define=API_BASE_URL="$API_BASE_URL"
./android/gradlew -p android :wear:assembleReleaseArtifact:
build/wear/outputs/apk/release/wear-release.apk
APK phone và watch phải có cùng application ID software.baycho.zmp3chart và
cùng signing certificate để Wear OS Data Layer cho phép giao tiếp. Cài mỗi APK
đúng thiết bị tương ứng; mở app điện thoại ít nhất một lần rồi mở #zingChart
Remote trên đồng hồ. Data Layer chỉ truyền state/lệnh qua kết nối cục bộ của
Android/Wear OS. Fire OS không cần Google Play Services để widget Android hoạt
động; Wear OS sync tự vô hiệu hóa khi Play Services không có.
Android runner đã có Leanback launcher, TV banner và đánh dấu touchscreen là không bắt buộc. AAB Android bình thường có thể phục vụ cả phone/tablet/TV.
Để tạo APK ép giao diện TV phục vụ sideload/test:
fvm flutter build apk --release \
--dart-define=API_BASE_URL="$API_BASE_URL" \
--dart-define=TV_MODE=trueCài lên TV hoặc emulator:
adb connect <ANDROID_TV_IP>:5555
adb install -r build/app/outputs/flutter-apk/app-release.apkYêu cầu macOS, full Xcode, CocoaPods và deployment target iOS 13+.
Tạo/cập nhật target WidgetKit và watchOS theo version trong pubspec.yaml:
gem install xcodeproj -v 1.27.0 --no-document
ruby packaging/apple/prepare_ios_companions.rbBuild app không ký để kiểm tra CI:
fvm flutter build ios --release --no-codesign \
--dart-define=API_BASE_URL="$API_BASE_URL"Artifact app bundle:
build/ios/iphoneos/Runner.app
Build IPA khi Xcode đã cấu hình Team, certificate và provisioning profile:
fvm flutter build ipa --release \
--dart-define=API_BASE_URL="$API_BASE_URL"IPA nằm trong build/ios/ipa/. Có thể mở ios/Runner.xcworkspace bằng Xcode,
chọn thiết bị thật, cấu hình Signing & Capabilities rồi dùng Product → Archive
để cài qua TestFlight hoặc phương thức phân phối phù hợp.
Widget tương tác yêu cầu iOS/iPadOS 17+. Trong Apple Developer, đăng ký thêm:
- App Group
group.software.baycho.zmp3chart.shared; - bundle ID
software.baycho.zmp3chart.widget; - bundle ID
software.baycho.zmp3chart.watchkitapp; - provisioning profile riêng cho Runner, Widget và Watch, nhưng cùng team và distribution certificate.
Sau khi cài, thêm #zingChart Widget từ Widget Gallery. Trên Apple Watch, cài #zingChart Remote từ ứng dụng Watch của iPhone. WatchConnectivity chỉ làm remote cho app iPhone; watch không tải audio và không gửi analytics lên mạng.
fvm flutter build web --release \
--dart-define=API_BASE_URL="$API_BASE_URL"Khi triển khai dưới subpath /app/, phải build đúng base href:
fvm flutter build web --release \
--base-href /app/ \
--dart-define=API_BASE_URL="$API_BASE_URL"Artifact: build/web/.
Smoke test local:
python3 -m http.server 8081 --directory build/webMở http://localhost:8081. Khi triển khai production, static host phải:
- phục vụ HTTPS;
- fallback route về
index.html; với subpath/app/, rewrite/app/*về/app/index.html; - không cache lâu file audio hoặc signed stream URL;
- có origin nằm trong
CORS_ORIGINScủa proxy.
Đóng tab hoặc trình duyệt sẽ kết thúc playback Web; autoplay lần đầu cần thao tác của người dùng.
Chỉ build Windows trên máy Windows:
$env:API_BASE_URL = "https://proxy.example.com"
fvm flutter config --enable-windows-desktop
fvm flutter pub get
fvm flutter build windows --release `
--dart-define=API_BASE_URL="$env:API_BASE_URL"Bundle chạy trực tiếp:
build/windows/x64/runner/Release/
Chạy zmp3chart.exe trong thư mục này; không tách riêng EXE khỏi DLL/data.
Cài Inno Setup 6, sau đó:
./packaging/windows/package_windows.ps1 -Version 1.0.0Artifact:
dist/windows/zingchart-windows-portable.zipdist/windows/zingchart-windows-installer.exe
MSIX cần Windows 10/11 SDK và Microsoft.VCLibs.Desktop 14.0 SDK:
./packaging/windows/package_msix.ps1 -Version 1.0.0Mặc định script tạo dist/windows/zingchart-windows-development.msix chưa ký
và copy VCLibs dependency. CI release tạo thêm development certificate cùng
script cài đặt. Trên máy test dùng PowerShell chạy với quyền Administrator:
PowerShell.exe -NoProfile -ExecutionPolicy Bypass `
-File .\install-zingchart-development.ps1Đối với Microsoft Store, Publisher, IdentityName và
PublisherDisplayName phải khớp chính xác Partner Center. Đây là Flutter Win32
được đóng gói MSIX, không phải UWP runner.
Yêu cầu full Xcode:
fvm flutter config --enable-macos-desktop
fvm flutter pub get
gem install xcodeproj -v 1.27.0 --no-document
ruby packaging/apple/prepare_macos_widget.rb
fvm flutter build macos --release \
--dart-define=API_BASE_URL="$API_BASE_URL"
./packaging/macos/package_macos.shArtifact:
build/macos/Build/Products/Release/#zingChart.appdist/macos/zingchart-macos-app.zipdist/macos/zingchart-macos.dmg
Mở DMG và kéo app vào Applications. Bản phát hành bên ngoài máy phát triển cần Developer ID signing, hardened runtime, notarization và stapling.
WidgetKit yêu cầu macOS 14+ và App Group
group.software.baycho.zmp3chart.shared. Sau khi cài app, mở Notification
Center → Edit Widgets → thêm #zingChart. Windows và Linux tiếp tục dùng
SMTC/MPRIS vì không có một home-widget API chung tương đương trong codebase.
Trên Ubuntu 22.04:
sudo apt-get update
sudo apt-get install -y \
clang cmake ninja-build pkg-config \
libgtk-3-dev liblzma-dev libfuse2 \
libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
fvm flutter config --enable-linux-desktop
fvm flutter pub get
fvm flutter build linux --release \
--dart-define=API_BASE_URL="$API_BASE_URL"Bundle chạy trực tiếp:
build/linux/x64/release/bundle/
Tạo tar.gz và DEB:
./packaging/linux/package_linux.sh "$VERSION"Tạo thêm AppImage bằng linuxdeploy đã được tải và xác minh checksum:
LINUXDEPLOY=/absolute/path/to/linuxdeploy \
./packaging/linux/package_linux.sh "$VERSION"Artifact:
dist/linux/zingchart-linux-portable.tar.gzdist/linux/zingchart_<version>_amd64.debdist/linux/zingchart-linux.AppImagenếu cóLINUXDEPLOY
Cài DEB:
sudo apt install ./dist/linux/zingchart_1.0.0_amd64.debFire OS dùng Android runtime. Script touch tạo APK riêng cho Amazon và không phụ thuộc Google Play Services:
FIREOS_FLUTTER_BIN="$(fvm which flutter)" \
FIREOS_BUILD_NUMBER=1 \
./packaging/fireos/build_fireos.sh \
"$API_BASE_URL" "$VERSION" touchArtifact:
dist/fireos/zingchart-fireos-1.0.0-development.apk
Nếu android/key.properties đã cấu hình, hậu tố -development được bỏ. CI
Amazon release bắt buộc production signing và dừng build khi thiếu secret.
Cài lên Fire tablet:
adb install -r dist/fireos/zingchart-fireos-1.0.0-development.apkFire Phone đời cũ không nằm trong phạm vi hỗ trợ; Flutter build hiện yêu cầu Android API tối thiểu của project.
FIREOS_FLUTTER_BIN="$(fvm which flutter)" \
FIREOS_BUILD_NUMBER=1 \
./packaging/fireos/build_fireos.sh \
"$API_BASE_URL" "$VERSION" tvArtifact:
dist/firetv/zingchart-firetv-1.0.0-development.apk
Cài qua mạng:
adb connect <FIRE_TV_IP>:5555
adb install -r dist/firetv/zingchart-firetv-1.0.0-development.apkVới FIREOS_BUILD_NUMBER=N, touch dùng versionCode N*2, Fire TV dùng
N*2+1. Tăng N ở mỗi release và ánh xạ hai APK vào đúng nhóm thiết bị trong
Amazon Developer Console.
Hỗ trợ package Flutter Web cho webOS TV 24+.
Cài CLI chính thức:
npm install --global @webos-tools/cli@3.2.5Build IPK:
TV_FLUTTER_BIN="$(fvm which flutter)" \
./packaging/tv/build_tv_web.sh \
webos "$API_BASE_URL" "$VERSION"Artifact nằm trong dist/webos/*.ipk.
Khai báo TV bằng ares-setup-device, sau đó cài và chạy:
ares-install --device <DEVICE_NAME> dist/webos/<PACKAGE_FILE>.ipk
ares-launch --device <DEVICE_NAME> software.baycho.app.zingchartProxy phục vụ package TV phải thêm literal null vào CORS_ORIGINS. Nên dùng
proxy riêng cho TV vì nhiều file/sandbox origin khác cũng có giá trị null.
Hỗ trợ package Web cho Tizen TV 8.0+.
Tạo project ZIP có thể ký:
TV_FLUTTER_BIN="$(fvm which flutter)" \
./packaging/tv/build_tv_web.sh \
tizen "$API_BASE_URL" "$VERSION"Artifact:
dist/tizen/zingchart-tizen-project-1.0.0.zip
Tạo WGT bằng profile chứng thư Samsung trong Tizen Studio:
./packaging/tv/package_tizen.sh <SAMSUNG_CERT_PROFILE>WGT được ghi vào dist/tizen/. Bật Developer Mode trên TV, kết nối bằng Tizen
Device Manager hoặc SDB rồi cài:
sdb connect <TV_IP>
sdb install dist/tizen/<PACKAGE_FILE>.wgtGiữ an toàn author certificate; mọi bản update phải dùng cùng certificate.
Proxy Tizen package cũng cần origin null trong CORS allowlist.
HarmonyOS dùng CPF-Flutter OHOS riêng, không dùng Flutter upstream. Pipeline được khóa với:
- CPF-Flutter
3.41.10-ohos-1.0.0; - Dart
3.11.5; - HarmonyOS SDK
5.1.0API 18; - dependency lock và plugin fork trong
packaging/harmonyos/.
Cài toolchain và cấu hình:
git clone --branch 3.41.10-ohos-1.0.0 \
https://gitcode.com/CPF-Flutter/flutter_flutter.git \
../flutter-ohos
export HARMONY_FLUTTER_BIN="$PWD/../flutter-ohos/bin/flutter"
export DEVECO_SDK_HOME=/path/to/HarmonyOS/sdk
export PATH="/path/to/DevEco-Studio/tools/ohpm/bin:/path/to/DevEco-Studio/tools/hvigor/bin:/path/to/DevEco-Studio/tools/node/bin:$PATH"Build HAP:
HARMONY_BUILD_NUMBER=1 \
./packaging/harmonyos/build_harmonyos.sh \
"$API_BASE_URL" "$VERSION"Artifact:
dist/harmonyos/zingchart-harmonyos-1.0.0.hap
Cài bằng DevEco Studio hoặc HDC sau khi thiết bị đã cho phép debug:
hdc install -r dist/harmonyos/zingchart-harmonyos-1.0.0.hapDEVECO_SDK_HOME phải chứa DevEco HarmonyOS sdk-pkg.json có API 18. Chỉ có
thư mục OpenHarmony tên 18 không đủ để build HAP. Phát hành AppGallery cần
signing profile thật.
Các plugin file picker/share hiện chưa có OHOS implementation đã được review; backup UI sẽ fallback sang copy/paste JSON trên HarmonyOS.
Build script đồng thời chèn HarmonyOS Service Widget 2×4, lưu snapshot trong
Preferences cục bộ và gọi cùng MethodChannel companion. Sau khi cài HAP, thêm
card #zingChart đang phát từ màn hình chính. Các nút card có thể đánh thức
EntryAbility để chuyển lệnh vào Flutter; không dùng endpoint proxy mới.
App lưu favorites, nghệ sĩ đã quan tâm, album/playlist Zing đã lưu, playlist cá nhân, queue, history, recent searches, theme và phiên phát trên từng thiết bị; không có tài khoản hoặc cloud sync riêng.
Trong Thư viện → Dữ liệu của bạn:
- Xuất backup JSON tạo
zingchart-library-YYYY-MM-DD.json. - Hợp nhất giữ dữ liệu hiện tại, loại record/bài trùng ID và chỉ lấy playlist metadata mới hơn.
- Ghi đè thay toàn bộ thư viện và theme bằng nội dung file.
- Import bị giới hạn 5 MB và không chứa audio hoặc signed stream URL.
Android Auto Backup/Device Transfer bao gồm AndroidX DataStore hiện tại và SharedPreferences legacy. iOS đưa dữ liệu app container vào device iCloud Backup theo chính sách hệ điều hành; đây không phải đồng bộ realtime.
.github/workflows/ci.yml chạy khi push lên main, develop, pull request hoặc
workflow dispatch. Pipeline kiểm tra:
- format, analyze và Flutter tests;
- Web/Android TV/Fire OS/TV package smoke builds và Wear OS APK;
- contract tests cho Android/iOS/macOS/HarmonyOS widget và watch remote;
- Windows MSIX layout;
- proxy typecheck/test/build và Docker smoke build.
Chạy Actions → Multiplatform Release → Run workflow với version x.y.z,
hoặc push tag:
git tag v1.0.0
git push origin v1.0.0API_BASE_URL nên được cấu hình bằng repository secret. Các signing secrets
chính:
| Nền tảng | Secrets/variables |
|---|---|
| Android/Fire OS | ANDROID_KEYSTORE_BASE64, ANDROID_KEY_ALIAS, ANDROID_KEY_PASSWORD, ANDROID_STORE_PASSWORD |
| Windows EXE | WINDOWS_CERTIFICATE_BASE64, WINDOWS_CERTIFICATE_PASSWORD |
| Windows Store MSIX | WINDOWS_PUBLISHER, WINDOWS_IDENTITY_NAME, WINDOWS_PUBLISHER_DISPLAY_NAME |
| Windows direct MSIX | WINDOWS_MSIX_CERTIFICATE_BASE64, WINDOWS_MSIX_CERTIFICATE_PASSWORD |
| macOS | MACOS_CERTIFICATE_BASE64, MACOS_CERTIFICATE_PASSWORD, MACOS_SIGNING_IDENTITY, Apple notarization secrets |
| iOS/Widget/watchOS | IOS_CERTIFICATE_BASE64, IOS_CERTIFICATE_PASSWORD, IOS_PROVISIONING_PROFILE_BASE64, IOS_WIDGET_PROVISIONING_PROFILE_BASE64, IOS_WATCH_PROVISIONING_PROFILE_BASE64, IOS_SIGNING_IDENTITY |
| Linux AppImage | LINUXDEPLOY_SHA256 |
| HarmonyOS | self-hosted runner variables HARMONY_FLUTTER_BIN, DEVECO_SDK_HOME, tùy chọn DEVECO_TOOL_HOME |
Chi tiết signing và artifact xem thêm tại
packaging/README.md. Proxy contract và security xem tại
proxy/README.md.
| Nền tảng | Artifact |
|---|---|
| Android | APK, AAB |
| Wear OS | zingchart-wearos-remote.apk |
| Android TV | APK/AAB universal hoặc APK ép TV_MODE=true |
| iOS/iPadOS/watchOS | unsigned app ZIP có WidgetKit/watchOS bundle; IPA khi đủ ba provisioning profile |
| Web/PWA | build/web/ hoặc tar.gz trong CI |
| Windows | portable ZIP, Inno EXE, MSIX |
| macOS | .app ZIP, DMG có WidgetKit extension |
| Linux | tar.gz, DEB, tùy chọn AppImage |
| Fire OS | touch APK |
| Fire TV | TV APK |
| webOS TV | IPK |
| Tizen TV | signable project ZIP, WGT sau khi ký |
| HarmonyOS | HAP có Service Widget |
| Proxy | Docker image tar.gz trong release CI |
- Release build thiếu
API_BASE_URLhoặc URL không phải HTTPS. - Build đang dùng placeholder
https://api.example.invalid. - CORS proxy chưa cho phép origin của Web/TV client.
- Kiểm tra
/v1/songs/{code}/sourcetrả URL cùng proxy origin. - Kiểm tra
/v1/streams/{token}hỗ trợ byte range. - Development cho phép
localhost,127.0.0.1và::1cùng port; production vẫn yêu cầu HTTPS và đúng origin proxy. - Lần phát đầu tiên phải bắt đầu từ thao tác người dùng do autoplay policy.
Tạo android/app/release.jks và android/key.properties trước khi build.
Không upload debug-signed artifact lên Store.
Command Line Tools không đủ. Cài full Xcode, chọn đúng developer directory và
chạy lại fvm flutter doctor -v.
- Thiết bị chưa đạt iOS/iPadOS 17 hoặc macOS 14.
- Runner và Widget chưa cùng App Group hoặc provisioning profile thiếu entitlement App Group.
- Chưa chạy lại script
prepare_ios_companions.rb/prepare_macos_widget.rbsau khi đổi version/project.
- Phone/watch APK không cùng application ID hoặc signing certificate.
- Đồng hồ chưa ghép với Android phone, app phone chưa mở, hoặc Google Play Services/Wear Data Layer không khả dụng.
- Wear OS remote không giao tiếp với iPhone; iPhone dùng watchOS target riêng.
- Package chưa ký hoặc certificate subject không khớp
Publisher. - Thiếu Microsoft.VCLibs.Desktop x64 dependency.
- Development installer phải chạy trong PowerShell Administrator.
package_linux.sh vẫn tạo tar.gz và DEB. AppImage chỉ được tạo khi biến
LINUXDEPLOY trỏ tới executable đã được xác minh checksum.
Thêm literal null vào CORS_ORIGINS của proxy TV và giữ rate limit. Không mở
* cho production.
DEVECO_SDK_HOME đang trỏ tới OpenHarmony SDK không tương thích hoặc thiếu
DevEco HarmonyOS API 18 metadata. Cài đúng HarmonyOS SDK từ DevEco Studio.
- Store submission và auto-update chưa được tự động hóa.
- Artifact không có signing secret chỉ dành cho development/test.
- Background playback, lock screen metadata, media keys và TV remote cần kiểm tra thêm trên thiết bị thật trước mỗi release.
- Widget/watch cần kiểm tra thêm trên launcher, Apple Watch, Wear OS và HarmonyOS hardware thật; CI không mô phỏng ghép đôi thiết bị.
- Nguồn Zing là upstream bên ngoài và có thể thay đổi; mọi thay đổi adapter phải được cô lập trong proxy.
- Chỉ sử dụng, relay hoặc tải nội dung khi có quyền phù hợp.



















































