fix(history): distinguish subtitle and audio records

This commit is contained in:
jxxghp
2026-09-06 16:29:59 +08:00
parent 2e85480484
commit 33bb01ab9d
5 changed files with 109 additions and 3 deletions
+4
View File
@@ -4728,6 +4728,10 @@ export default {
success: 'Success',
failed: 'Failed',
},
category: {
subtitle: 'Subtitle',
audio: 'Audio',
},
deleteStep: {
source: 'Source file',
destination: 'Media library file',
+4
View File
@@ -4632,6 +4632,10 @@ export default {
success: '成功',
failed: '失败',
},
category: {
subtitle: '字幕',
audio: '音频',
},
deleteStep: {
source: '源文件',
destination: '媒体库文件',
+4
View File
@@ -4573,6 +4573,10 @@ export default {
success: '成功',
failed: '失敗',
},
category: {
subtitle: '字幕',
audio: '音訊',
},
deleteStep: {
source: '來源檔案',
destination: '媒體庫檔案',
+62 -3
View File
@@ -1388,9 +1388,68 @@ function getHistoryDisplayTitle(item: TransferHistory) {
//
function getHistorySubtitle(item: TransferHistory) {
return [item.category, item.year, item.type === '音乐' ? formatMusicAudioSpecs(item) : ''].filter(Boolean).join(' / ')
return [getHistoryCategory(item), item.year, item.type === '音乐' ? formatMusicAudioSpecs(item) : '']
.filter(Boolean)
.join(' / ')
}
// /
function getHistoryCategory(item: TransferHistory) {
const rawExtension = item.src_fileitem?.extension || getFileExtension(item.src)
const extension = rawExtension ? `.${rawExtension.replace(/^\./, '').toLowerCase()}` : ''
if (subtitleExtensions.has(extension)) return t('transferHistory.category.subtitle')
if (audioExtensions.has(extension) && item.type !== '音乐') return t('transferHistory.category.audio')
return item.category
}
function getFileExtension(path?: string) {
const filename = path?.split(/[\\/]/).at(-1) || ''
const dot = filename.lastIndexOf('.')
return dot >= 0 ? filename.slice(dot) : ''
}
const subtitleExtensions = new Set(['.srt', '.ass', '.ssa', '.sup'])
const audioExtensions = new Set([
'.aac',
'.ac3',
'.amr',
'.caf',
'.cda',
'.dsf',
'.dff',
'.kar',
'.m4a',
'.mp1',
'.mp2',
'.mp3',
'.mid',
'.mod',
'.mka',
'.mpc',
'.nsf',
'.ogg',
'.pcm',
'.rmi',
'.s3m',
'.snd',
'.spx',
'.tak',
'.tta',
'.vqf',
'.wav',
'.wma',
'.aifc',
'.aiff',
'.alac',
'.adif',
'.adts',
'.ape',
'.flac',
'.midi',
'.opus',
'.sfalc',
])
// 退
function getHistoryStorageName(storage?: string) {
if (!storage) return t('common.unknown')
@@ -1849,7 +1908,7 @@ onUnmounted(() => {
<span v-if="item.type === '电视剧'" class="d-block text-high-emphasis min-w-20">
{{ item?.seasons }}{{ item?.episodes }}
</span>
<small>{{ item?.category }}</small>
<small>{{ getHistoryCategory(item) }}</small>
</div>
</div>
</template>
@@ -1955,7 +2014,7 @@ onUnmounted(() => {
<span v-else class="d-block text-high-emphasis min-w-20">
{{ item?.title }}
</span>
<small>{{ item?.category }}</small>
<small>{{ getHistoryCategory(item) }}</small>
</div>
</div>
</template>
@@ -963,6 +963,41 @@ describe('TransferHistoryView', () => {
expect(await screen.findByText('华语流行 / 2003 / FLAC · 24-bit · 96 kHz · 2,304 kbps')).toBeInTheDocument()
})
it('shows subtitle and attached audio as distinct history categories', async () => {
mocks.desktop = false
const histories = [
createHistory(1, '字幕文件', {
category: '电影',
image: '/subtitle-poster.jpg',
src: '/downloads/电影.zh.srt',
src_fileitem: { extension: 'srt', size: 100 } as TransferHistory['src_fileitem'],
}),
createHistory(2, '音频文件', {
category: '电影',
image: '/audio-poster.jpg',
src: '/downloads/电影.commentary.mka',
src_fileitem: { extension: 'mka', size: 200 } as TransferHistory['src_fileitem'],
}),
createHistory(3, '正常媒体', {
category: '动作',
image: '/movie-poster.jpg',
src: '/downloads/电影.mkv',
src_fileitem: { extension: 'mkv', size: 300 } as TransferHistory['src_fileitem'],
}),
]
mocks.apiGet.mockImplementation((path: string) => {
if (path === 'storage/options') return Promise.resolve(storageResponse())
return Promise.resolve(historyResponse(histories))
})
await renderHistory()
await fireEvent.click(screen.getByRole('button', { name: '加载下一页' }))
expect(await screen.findByText('字幕')).toBeInTheDocument()
expect(screen.getByText('音频')).toBeInTheDocument()
expect(screen.getByText('动作')).toBeInTheDocument()
})
it('prevents a mobile request invalidated by a route reset from appending stale records', async () => {
mocks.desktop = false
const oldRequest = createDeferred<ReturnType<typeof historyResponse>>()