feat: expose playlist sharing over HTTP

This commit is contained in:
DiheChen committed 2026-11-11 00:08:57 +08:00
1 parent eed25578c7
commit 8b941764b1
13 files changed
+743 -19

No files matched your search

+15 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protocolgen from protocol/idl.json; DO NOT EDIT.
import type { APIKey, Account, AdminAccount, ErrorInfo, ImportedTrack, Member, MyListen, MyPlaylist, MyPlaylistItem, QQLoginType, QRLogin, QRLoginResult, RoomListing, Source, SourceAccount, StoredMedia, Track } from '../realtime/protocol.gen'
import type { APIKey, Account, AdminAccount, ErrorInfo, ImportedTrack, Member, MyListen, MyPlaylist, MyPlaylistItem, QQLoginType, QRLogin, QRLoginResult, RoomListing, SharedPlaylist, Source, SourceAccount, StoredMedia, Track } from '../realtime/protocol.gen'
export interface AddMyPlaylistItemRequest {
track: Track
@@ -118,6 +118,10 @@ export interface CopyMyPlaylistItemsResponse {
added: number
}
export interface CopySharedPlaylistRequest {
name: string
}
export type CreateMemberRequest = Record<string, never>
export interface CreateMemberResponse {
@@ -253,6 +257,12 @@ export interface ResolveMyPlaylistLinkResponse {
source: Source
}
export type ShareMyPlaylistRequest = Record<string, never>
export interface ShareMyPlaylistResponse {
shareId: string
}
export interface UpdateMeRequest {
email?: string
name?: string
@@ -334,5 +344,9 @@ export function httpClient(send: HttpSend) {
clearMyListens: () => send<void>({ method: 'DELETE', path: '/api/me/listens', auth: 'member' }),
enableListenRecording: () => send<void>({ method: 'PUT', path: '/api/me/listen-recording', auth: 'member', body: {} }),
disableListenRecording: () => send<void>({ method: 'DELETE', path: '/api/me/listen-recording', auth: 'member' }),
shareMyPlaylist: (id: string) => send<ShareMyPlaylistResponse>({ method: 'POST', path: `/api/me/playlists/${encodeURIComponent(id)}/share`, auth: 'member', body: {} }),
unshareMyPlaylist: (id: string) => send<void>({ method: 'DELETE', path: `/api/me/playlists/${encodeURIComponent(id)}/share`, auth: 'member' }),
getSharedPlaylist: (shareId: string) => send<SharedPlaylist>({ method: 'GET', path: `/api/shared-playlists/${encodeURIComponent(shareId)}`, auth: 'none' }),
copySharedPlaylist: (shareId: string, body: CopySharedPlaylistRequest) => send<MyPlaylist>({ method: 'POST', path: `/api/shared-playlists/${encodeURIComponent(shareId)}/copies`, auth: 'member', body }),
}
}
+10 -1
View File
@@ -1,6 +1,6 @@
// Code generated by protocolgen from protocol/idl.json; DO NOT EDIT.
export const PROTOCOL_VERSION = 'ae9a632d648f3840'
export const PROTOCOL_VERSION = 'cbfa923a9cbe9f0a'
export interface APIKey {
key: string
@@ -94,6 +94,7 @@ export interface MyPlaylist {
favorites: boolean
id: string
name: string
shareId: string | null
trackCount: number
updatedAtMs: number
}
@@ -284,6 +285,14 @@ export interface SettingsUpdatedEvent {
playMode: PlayMode
}
export interface SharedPlaylist {
favorites: boolean
items: MyPlaylistItem[]
name: string
ownerAvatarHash: string
ownerName: string
}
export type Source = 'netease' | 'qq' | 'bilibili' | 'link'
export interface SourceAccount {
@@ -4,7 +4,7 @@ import { describe, expect, it } from 'vitest'
import { sortPlaylists } from './playlist-sort'
function playlist(id: string, name: string, trackCount: number, createdAtMs: number, updatedAtMs: number, favorites = false): MyPlaylist {
return { id, name, favorites, trackCount, createdAtMs, updatedAtMs, coverUrl: null }
return { id, name, favorites, trackCount, createdAtMs, updatedAtMs, coverUrl: null, shareId: null }
}
const favorites = playlist('p0', '我喜欢', 3, 50, 50, true)
@@ -25,15 +25,15 @@ class FakeStorage {
}
}
const favorites = { id: 'p1', name: '我喜欢', favorites: true, trackCount: 1, createdAtMs: 1, updatedAtMs: 1, coverUrl: null }
const favorites = { id: 'p1', name: '我喜欢', favorites: true, trackCount: 1, createdAtMs: 1, updatedAtMs: 1, coverUrl: null, shareId: null }
const sunny = { source: 'netease', id: '186016' } as const
const rain = { source: 'netease', id: '185811' } as const
const commute = { id: 'p2', name: '通勤', favorites: false, trackCount: 0, createdAtMs: 1, updatedAtMs: 1, coverUrl: null }
const commute = { id: 'p2', name: '通勤', favorites: false, trackCount: 0, createdAtMs: 1, updatedAtMs: 1, coverUrl: null, shareId: null }
const meta = { title: '晴天', artist: '周杰伦', album: '叶惠美', coverUrl: '', pageUrl: '', durationMs: 0 }
const notReady = '这首歌还在准备,准备好之后再保存'
const full = '一个歌单最多 1000 首歌'
const changed = '歌单已经变了,刷新之后再试'
const imported = { id: 'p3', name: '导入的歌单', favorites: false, trackCount: 2, createdAtMs: 2, updatedAtMs: 2, coverUrl: null }
const imported = { id: 'p3', name: '导入的歌单', favorites: false, trackCount: 2, createdAtMs: 2, updatedAtMs: 2, coverUrl: null, shareId: null }
const fileTrack = { track: sunny, title: '晴天', durationMs: 269000 }
let requests: string[]