albums.service.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.albumsService = exports.AlbumsService = void 0;
  4. const models_1 = require("../../models");
  5. /**
  6. * 专辑服务
  7. */
  8. class AlbumsService {
  9. /**
  10. * 获取或创建默认专辑
  11. */
  12. async getOrCreateDefaultAlbum() {
  13. let defaultAlbum = await models_1.prisma.album.findFirst({
  14. where: { isDefault: true },
  15. });
  16. if (!defaultAlbum) {
  17. defaultAlbum = await models_1.prisma.album.create({
  18. data: {
  19. name: '默认专辑',
  20. description: '包含所有未归类音频的默认专辑',
  21. isDefault: true,
  22. },
  23. });
  24. }
  25. return defaultAlbum;
  26. }
  27. /**
  28. * 创建专辑
  29. */
  30. async createAlbum(data) {
  31. return models_1.prisma.album.create({
  32. data: {
  33. name: data.name,
  34. description: data.description,
  35. coverUrl: data.coverUrl,
  36. userId: data.userId,
  37. },
  38. });
  39. }
  40. /**
  41. * 获取专辑列表
  42. */
  43. async getAlbums(options) {
  44. const { page = 1, pageSize = 20 } = options || {};
  45. const [albums, total] = await Promise.all([
  46. models_1.prisma.album.findMany({
  47. skip: (page - 1) * pageSize,
  48. take: pageSize,
  49. orderBy: { createdAt: 'desc' },
  50. include: {
  51. _count: {
  52. select: { subscriptions: true, albumAudios: true },
  53. },
  54. },
  55. }),
  56. models_1.prisma.album.count(),
  57. ]);
  58. // 获取所有未分类的音频数量
  59. const uncategorizedCount = await models_1.prisma.audio.count({
  60. where: { albumId: null, status: 'completed' },
  61. });
  62. return {
  63. list: albums.map((album) => {
  64. // 默认专辑需要加上未分类音频的数量
  65. const audioCount = album.isDefault
  66. ? album._count?.albumAudios + uncategorizedCount
  67. : album._count?.albumAudios;
  68. return {
  69. ...album,
  70. subscriberCount: album._count?.subscriptions || 0,
  71. audioCount: audioCount || 0,
  72. _count: undefined,
  73. };
  74. }),
  75. total,
  76. page,
  77. pageSize,
  78. totalPages: Math.ceil(total / pageSize),
  79. };
  80. }
  81. /**
  82. * 获取专辑详情
  83. */
  84. async getAlbumById(albumId) {
  85. const album = await models_1.prisma.album.findUnique({
  86. where: { id: albumId },
  87. include: {
  88. _count: {
  89. select: { subscriptions: true },
  90. },
  91. },
  92. });
  93. if (!album) {
  94. throw new Error('专辑不存在');
  95. }
  96. return {
  97. ...album,
  98. subscriberCount: album._count?.subscriptions || 0,
  99. _count: undefined,
  100. };
  101. }
  102. /**
  103. * 更新专辑
  104. */
  105. async updateAlbum(albumId, data) {
  106. return models_1.prisma.album.update({
  107. where: { id: albumId },
  108. data: {
  109. name: data.name,
  110. description: data.description,
  111. coverUrl: data.coverUrl,
  112. },
  113. });
  114. }
  115. /**
  116. * 删除专辑
  117. */
  118. async deleteAlbum(albumId) {
  119. await models_1.prisma.album.delete({
  120. where: { id: albumId },
  121. });
  122. }
  123. /**
  124. * 获取专辑内的音频列表
  125. */
  126. async getAlbumAudios(albumId) {
  127. // 检查是否是默认专辑
  128. const album = await models_1.prisma.album.findUnique({ where: { id: albumId } });
  129. const isDefault = album?.isDefault || false;
  130. // 获取通过 albumId 直接关联的音频
  131. const directAudios = await models_1.prisma.audio.findMany({
  132. where: { albumId },
  133. orderBy: { createdAt: 'desc' },
  134. });
  135. // 获取通过 AlbumAudio 中间表关联的音频
  136. const albumAudios = await models_1.prisma.albumAudio.findMany({
  137. where: { albumId },
  138. include: {
  139. audio: true,
  140. },
  141. orderBy: { order: 'asc' },
  142. });
  143. // 如果是默认专辑,还需要获取 albumId 为 null 的音频
  144. let uncategorizedAudios = [];
  145. if (isDefault) {
  146. uncategorizedAudios = await models_1.prisma.audio.findMany({
  147. where: {
  148. albumId: null,
  149. status: 'completed',
  150. },
  151. orderBy: { createdAt: 'desc' },
  152. });
  153. }
  154. // 合并所有音频并去重
  155. const audioMap = new Map();
  156. // 先添加直接关联的音频
  157. directAudios.forEach((audio) => {
  158. audioMap.set(audio.id, audio);
  159. });
  160. // 添加中间表关联的音频
  161. albumAudios.forEach((aa) => {
  162. audioMap.set(aa.audio.id, {
  163. ...aa.audio,
  164. order: aa.order,
  165. addedAt: aa.addedAt,
  166. });
  167. });
  168. // 添加未分类音频
  169. uncategorizedAudios.forEach((audio) => {
  170. if (!audioMap.has(audio.id)) {
  171. audioMap.set(audio.id, audio);
  172. }
  173. });
  174. return Array.from(audioMap.values()).sort((a, b) => {
  175. // 按添加时间排序,如果没有添加时间则按创建时间
  176. const timeA = a.addedAt || a.createdAt;
  177. const timeB = b.addedAt || b.createdAt;
  178. return new Date(timeB).getTime() - new Date(timeA).getTime();
  179. });
  180. }
  181. /**
  182. * 添加音频到专辑
  183. */
  184. async addAudioToAlbum(albumId, audioId, order = 0) {
  185. // 检查专辑是否存在
  186. const album = await models_1.prisma.album.findUnique({ where: { id: albumId } });
  187. if (!album) {
  188. throw new Error('专辑不存在');
  189. }
  190. // 检查音频是否存在
  191. const audio = await models_1.prisma.audio.findUnique({ where: { id: audioId } });
  192. if (!audio) {
  193. throw new Error('音频不存在');
  194. }
  195. return models_1.prisma.albumAudio.create({
  196. data: {
  197. albumId,
  198. audioId,
  199. order,
  200. },
  201. });
  202. }
  203. /**
  204. * 从专辑移除音频
  205. */
  206. async removeAudioFromAlbum(albumId, audioId) {
  207. await models_1.prisma.albumAudio.delete({
  208. where: {
  209. albumId_audioId: {
  210. albumId,
  211. audioId,
  212. },
  213. },
  214. });
  215. }
  216. /**
  217. * 调整专辑中音频的顺序
  218. */
  219. async reorderAudio(albumId, audioId, order) {
  220. return models_1.prisma.albumAudio.update({
  221. where: {
  222. albumId_audioId: {
  223. albumId,
  224. audioId,
  225. },
  226. },
  227. data: { order },
  228. });
  229. }
  230. /**
  231. * 订阅专辑
  232. */
  233. async subscribeAlbum(userId, albumId) {
  234. // 检查专辑是否存在
  235. const album = await models_1.prisma.album.findUnique({ where: { id: albumId } });
  236. if (!album) {
  237. throw new Error('专辑不存在');
  238. }
  239. return models_1.prisma.albumSubscription.upsert({
  240. where: {
  241. userId_albumId: {
  242. userId,
  243. albumId,
  244. },
  245. },
  246. update: {},
  247. create: {
  248. userId,
  249. albumId,
  250. },
  251. });
  252. }
  253. /**
  254. * 取消订阅专辑
  255. */
  256. async unsubscribeAlbum(userId, albumId) {
  257. await models_1.prisma.albumSubscription.delete({
  258. where: {
  259. userId_albumId: {
  260. userId,
  261. albumId,
  262. },
  263. },
  264. });
  265. }
  266. /**
  267. * 获取用户已订阅的专辑列表
  268. */
  269. async getSubscribedAlbums(userId) {
  270. const subscriptions = await models_1.prisma.albumSubscription.findMany({
  271. where: { userId },
  272. include: {
  273. album: {
  274. include: {
  275. _count: {
  276. select: { subscriptions: true },
  277. },
  278. },
  279. },
  280. },
  281. orderBy: { createdAt: 'desc' },
  282. });
  283. return subscriptions.map((sub) => ({
  284. ...sub.album,
  285. subscriberCount: sub.album._count?.subscriptions || 0,
  286. subscribedAt: sub.createdAt,
  287. _count: undefined,
  288. }));
  289. }
  290. /**
  291. * 检查用户是否已订阅专辑
  292. */
  293. async isSubscribed(userId, albumId) {
  294. const subscription = await models_1.prisma.albumSubscription.findUnique({
  295. where: {
  296. userId_albumId: {
  297. userId,
  298. albumId,
  299. },
  300. },
  301. });
  302. return !!subscription;
  303. }
  304. }
  305. exports.AlbumsService = AlbumsService;
  306. // 导出单例
  307. exports.albumsService = new AlbumsService();