mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-03-26 11:30:37 +03:00
feat(Content/Filter): Group extensions of same type (#2204)
This commit is contained in:
parent
18eb8975ea
commit
ddbafbef68
9 changed files with 243 additions and 79 deletions
src
components
constants/vuetorrent
helpers
locales
|
@ -1,7 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import HistoryField from '@/components/Core/HistoryField.vue'
|
import HistoryField from '@/components/Core/HistoryField.vue'
|
||||||
import { useDialog } from '@/composables'
|
import { useDialog } from '@/composables'
|
||||||
import { getFileIcon, HistoryKey } from '@/constants/vuetorrent'
|
import { HistoryKey } from '@/constants/vuetorrent'
|
||||||
|
import { getFileIcon } from '@/helpers'
|
||||||
import { useContentStore } from '@/stores'
|
import { useContentStore } from '@/stores'
|
||||||
import { TreeFolder, TreeNode } from '@/types/vuetorrent'
|
import { TreeFolder, TreeNode } from '@/types/vuetorrent'
|
||||||
import { computed, onMounted, reactive, readonly, ref, watch } from 'vue'
|
import { computed, onMounted, reactive, readonly, ref, watch } from 'vue'
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useDialog } from '@/composables'
|
import { useDialog, useI18nUtils } from '@/composables'
|
||||||
import { FilePriority } from '@/constants/qbit'
|
import { FilePriority } from '@/constants/qbit'
|
||||||
import { comparators, formatData } from '@/helpers'
|
import { FileType } from '@/constants/vuetorrent'
|
||||||
import { splitExt } from '@/helpers/path.ts'
|
import { comparators, formatData, getExtType, splitExt } from '@/helpers'
|
||||||
import { useContentStore, useVueTorrentStore } from '@/stores'
|
import { useContentStore, useVueTorrentStore } from '@/stores'
|
||||||
import { computed, reactive } from 'vue'
|
import { computed, reactive } from 'vue'
|
||||||
import { useI18nUtils } from '@/composables'
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
guid: string
|
guid: string
|
||||||
|
@ -21,15 +20,35 @@ const sizeBoundaries = computed<[number, number]>(() =>
|
||||||
.map(file => file.size)
|
.map(file => file.size)
|
||||||
.reduce((prev, curr) => [prev[0] === -1 || curr < prev[0] ? curr : prev[0], prev[1] === -1 || curr > prev[1] ? curr : prev[1]], [-1, -1])
|
.reduce((prev, curr) => [prev[0] === -1 || curr < prev[0] ? curr : prev[0], prev[1] === -1 || curr > prev[1] ? curr : prev[1]], [-1, -1])
|
||||||
)
|
)
|
||||||
const fileExtensions = computed(() => Array.from(new Set<string>(contentStore.cachedFiles.map(file => splitExt(file.name)[1])).values()))
|
|
||||||
const extensionItems = computed(() =>
|
const fileExtensionsByType = computed(() =>
|
||||||
fileExtensions.value
|
new Set<string>(contentStore.cachedFiles.map(file => splitExt(file.name)[1])).values().reduce(
|
||||||
.map(ext => {
|
(prev, ext) => {
|
||||||
if (ext === '') return { title: t('common.none'), value: '' }
|
const type = getExtType(ext)
|
||||||
else return { title: `.${ext}`, value: ext }
|
if (Object.keys(prev).includes(type)) {
|
||||||
})
|
prev[type].push(ext)
|
||||||
.sort((a, b) => comparators.text.asc(a.title, b.title))
|
} else {
|
||||||
|
prev[type] = [ext]
|
||||||
|
}
|
||||||
|
return prev
|
||||||
|
},
|
||||||
|
{} as Record<FileType, string[]>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
const extensionItems = computed(() =>
|
||||||
|
Object.entries(fileExtensionsByType.value)
|
||||||
|
.sort(([typeA, _1], [typeB, _2]) => {
|
||||||
|
if (typeA === FileType.UNKNOWN) return 1
|
||||||
|
if (typeB === FileType.UNKNOWN) return -1
|
||||||
|
return comparators.text.asc(typeA, typeB)
|
||||||
|
})
|
||||||
|
.flatMap(([type, extensions]) => [
|
||||||
|
{ props: { header: t(`constants.file_type.${type}`) } },
|
||||||
|
...extensions.map(ext => ({ title: `.${ext}`, value: ext })),
|
||||||
|
{ props: { divider: true } }
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
const priorityOptions = [
|
const priorityOptions = [
|
||||||
{
|
{
|
||||||
title: t('constants.file_priority.unwanted'),
|
title: t('constants.file_priority.unwanted'),
|
||||||
|
@ -91,30 +110,38 @@ function close() {
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="ios-margin">
|
<v-card-title class="ios-margin">
|
||||||
<v-toolbar color="transparent">
|
<v-toolbar color="transparent">
|
||||||
<v-toolbar-title>{{ $t('torrentDetail.content.filter.title') }}</v-toolbar-title>
|
<v-toolbar-title>{{ t('torrentDetail.content.filter.title') }}</v-toolbar-title>
|
||||||
<v-btn icon="mdi-close" @click="close" />
|
<v-btn icon="mdi-close" @click="close" />
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="4" class="d-flex align-center">
|
<v-col cols="4" class="d-flex align-center">
|
||||||
{{ $t('torrentDetail.content.filter.extensions') }}
|
{{ t('torrentDetail.content.filter.extensions') }}
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="8">
|
<v-col cols="8">
|
||||||
<v-select v-model="filters.extensions" :items="extensionItems" :placeholder="$t('common.disabled')" persistent-placeholder multiple hide-details />
|
<v-select v-model="filters.extensions" :items="extensionItems" :placeholder="t('common.disabled')" persistent-placeholder multiple hide-details>
|
||||||
|
<template #item="data">
|
||||||
|
<v-list-subheader v-if="data.props.header">
|
||||||
|
{{ data.props.header }}
|
||||||
|
</v-list-subheader>
|
||||||
|
<v-divider v-else-if="data.props.divider" />
|
||||||
|
<v-list-item v-else v-bind="data.props" />
|
||||||
|
</template>
|
||||||
|
</v-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="4" class="d-flex align-center">
|
<v-col cols="4" class="d-flex align-center">
|
||||||
{{ $t('torrentDetail.content.filter.priority') }}
|
{{ t('torrentDetail.content.filter.priority') }}
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="8">
|
<v-col cols="8">
|
||||||
<v-select v-model="filters.priority" :items="priorityOptions" :placeholder="$t('common.disabled')" persistent-placeholder multiple hide-details />
|
<v-select v-model="filters.priority" :items="priorityOptions" :placeholder="t('common.disabled')" persistent-placeholder multiple hide-details />
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="4" class="d-flex align-center">
|
<v-col cols="4" class="d-flex align-center">
|
||||||
{{ $t('torrentDetail.content.filter.size') }}
|
{{ t('torrentDetail.content.filter.size') }}
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="8">
|
<v-col cols="8">
|
||||||
<v-range-slider
|
<v-range-slider
|
||||||
|
@ -145,7 +172,7 @@ function close() {
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
{{
|
{{
|
||||||
$t('torrentDetail.content.filter.preview', {
|
t('torrentDetail.content.filter.preview', {
|
||||||
count: filterPreview.length,
|
count: filterPreview.length,
|
||||||
total: contentStore.cachedFiles.length,
|
total: contentStore.cachedFiles.length,
|
||||||
size: formatData(filterPreviewSize, vuetorrentStore.useBinarySize)
|
size: formatData(filterPreviewSize, vuetorrentStore.useBinarySize)
|
||||||
|
@ -155,8 +182,8 @@ function close() {
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-btn color="error" @click="exclude">{{ $t('torrentDetail.content.filter.exclude') }}</v-btn>
|
<v-btn color="error" @click="exclude">{{ t('torrentDetail.content.filter.exclude') }}</v-btn>
|
||||||
<v-btn color="success" @click="include">{{ $t('torrentDetail.content.filter.include') }}</v-btn>
|
<v-btn color="success" @click="include">{{ t('torrentDetail.content.filter.include') }}</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18nUtils } from '@/composables'
|
import { useI18nUtils } from '@/composables'
|
||||||
import { FilePriority } from '@/constants/qbit'
|
import { FilePriority } from '@/constants/qbit'
|
||||||
import { getFileIcon } from '@/constants/vuetorrent'
|
import { doesCommand, formatData, getFileIcon } from '@/helpers'
|
||||||
import { doesCommand, formatData } from '@/helpers'
|
|
||||||
import { useContentStore, useVueTorrentStore } from '@/stores'
|
import { useContentStore, useVueTorrentStore } from '@/stores'
|
||||||
import { TreeNode } from '@/types/vuetorrent'
|
import { TreeNode } from '@/types/vuetorrent'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
|
@ -1,57 +1,122 @@
|
||||||
enum FileIcon {
|
export enum FileType {
|
||||||
PDF = 'mdi-file-pdf-box',
|
ARCHIVE = 'archive',
|
||||||
IMAGE = 'mdi-file-image',
|
AUDIO = 'audio',
|
||||||
DOCUMENT = 'mdi-file-document',
|
BOOK = 'book',
|
||||||
INFORMATION = 'mdi-information-variant-box',
|
DOCUMENT = 'document',
|
||||||
MUSIC = 'mdi-music',
|
EXECUTABLE = 'executable',
|
||||||
VIDEO = 'mdi-movie',
|
IMAGE = 'image',
|
||||||
SUBTITLE = 'mdi-subtitles',
|
INFORMATION = 'information',
|
||||||
ARCHIVE = 'mdi-zip-box-outline',
|
SCRIPT = 'script',
|
||||||
EXECUTABLE = 'mdi-application-brackets'
|
SUBTITLE = 'subtitle',
|
||||||
|
VIDEO = 'video',
|
||||||
|
|
||||||
|
UNKNOWN = 'unknown'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const typesMap: Record<string, FileIcon> = {
|
export const typesMap: Record<FileType, string> = {
|
||||||
pdf: FileIcon.PDF,
|
[FileType.ARCHIVE]: 'mdi-zip-box-outline',
|
||||||
|
[FileType.AUDIO]: 'mdi-audio',
|
||||||
|
[FileType.BOOK]: 'mdi-book-open-blank-variant',
|
||||||
|
[FileType.DOCUMENT]: 'mdi-file-document',
|
||||||
|
[FileType.EXECUTABLE]: 'mdi-application-brackets',
|
||||||
|
[FileType.IMAGE]: 'mdi-file-image',
|
||||||
|
[FileType.INFORMATION]: 'mdi-information-variant-box',
|
||||||
|
[FileType.SCRIPT]: 'mdi-script-text',
|
||||||
|
[FileType.SUBTITLE]: 'mdi-subtitles',
|
||||||
|
[FileType.VIDEO]: 'mdi-movie',
|
||||||
|
|
||||||
png: FileIcon.IMAGE,
|
[FileType.UNKNOWN]: 'mdi-file'
|
||||||
jpg: FileIcon.IMAGE,
|
|
||||||
jpeg: FileIcon.IMAGE,
|
|
||||||
tiff: FileIcon.IMAGE,
|
|
||||||
|
|
||||||
doc: FileIcon.DOCUMENT,
|
|
||||||
docx: FileIcon.DOCUMENT,
|
|
||||||
txt: FileIcon.DOCUMENT,
|
|
||||||
|
|
||||||
nfo: FileIcon.INFORMATION,
|
|
||||||
|
|
||||||
mp3: FileIcon.MUSIC,
|
|
||||||
wav: FileIcon.MUSIC,
|
|
||||||
flac: FileIcon.MUSIC,
|
|
||||||
|
|
||||||
avi: FileIcon.VIDEO,
|
|
||||||
mp4: FileIcon.VIDEO,
|
|
||||||
mkv: FileIcon.VIDEO,
|
|
||||||
mov: FileIcon.VIDEO,
|
|
||||||
wmv: FileIcon.VIDEO,
|
|
||||||
|
|
||||||
srt: FileIcon.SUBTITLE,
|
|
||||||
idx: FileIcon.SUBTITLE,
|
|
||||||
sub: FileIcon.SUBTITLE,
|
|
||||||
|
|
||||||
rar: FileIcon.ARCHIVE,
|
|
||||||
zip: FileIcon.ARCHIVE,
|
|
||||||
gz: FileIcon.ARCHIVE,
|
|
||||||
'7z': FileIcon.ARCHIVE,
|
|
||||||
iso: FileIcon.ARCHIVE,
|
|
||||||
|
|
||||||
exe: FileIcon.EXECUTABLE,
|
|
||||||
msi: FileIcon.EXECUTABLE,
|
|
||||||
dmg: FileIcon.EXECUTABLE,
|
|
||||||
deb: FileIcon.EXECUTABLE,
|
|
||||||
jar: FileIcon.EXECUTABLE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFileIcon(filename: string) {
|
export const extMap: Record<string, FileType> = {
|
||||||
const type = filename.split('.').pop()?.toLowerCase() || ''
|
'7z': FileType.ARCHIVE,
|
||||||
return typesMap[type] || 'mdi-file'
|
bz2: FileType.ARCHIVE,
|
||||||
|
cab: FileType.ARCHIVE,
|
||||||
|
gz: FileType.ARCHIVE,
|
||||||
|
iso: FileType.ARCHIVE,
|
||||||
|
rar: FileType.ARCHIVE,
|
||||||
|
sfx: FileType.ARCHIVE,
|
||||||
|
tar: FileType.ARCHIVE,
|
||||||
|
tgz: FileType.ARCHIVE,
|
||||||
|
xz: FileType.ARCHIVE,
|
||||||
|
zip: FileType.ARCHIVE,
|
||||||
|
|
||||||
|
alac: FileType.AUDIO,
|
||||||
|
flac: FileType.AUDIO,
|
||||||
|
mp3: FileType.AUDIO,
|
||||||
|
ogg: FileType.AUDIO,
|
||||||
|
wav: FileType.AUDIO,
|
||||||
|
wma: FileType.AUDIO,
|
||||||
|
|
||||||
|
cb7: FileType.BOOK,
|
||||||
|
cbr: FileType.BOOK,
|
||||||
|
cbt: FileType.BOOK,
|
||||||
|
cbz: FileType.BOOK,
|
||||||
|
epub: FileType.BOOK,
|
||||||
|
mobi: FileType.BOOK,
|
||||||
|
|
||||||
|
doc: FileType.DOCUMENT,
|
||||||
|
docx: FileType.DOCUMENT,
|
||||||
|
htm: FileType.DOCUMENT,
|
||||||
|
html: FileType.DOCUMENT,
|
||||||
|
pdf: FileType.DOCUMENT,
|
||||||
|
rtf: FileType.DOCUMENT,
|
||||||
|
txt: FileType.DOCUMENT,
|
||||||
|
xhtml: FileType.DOCUMENT,
|
||||||
|
|
||||||
|
apk: FileType.EXECUTABLE,
|
||||||
|
app: FileType.EXECUTABLE,
|
||||||
|
bin: FileType.EXECUTABLE,
|
||||||
|
deb: FileType.EXECUTABLE,
|
||||||
|
dmg: FileType.EXECUTABLE,
|
||||||
|
exe: FileType.EXECUTABLE,
|
||||||
|
jar: FileType.EXECUTABLE,
|
||||||
|
msi: FileType.EXECUTABLE,
|
||||||
|
|
||||||
|
avif: FileType.IMAGE,
|
||||||
|
bmp: FileType.IMAGE,
|
||||||
|
gif: FileType.IMAGE,
|
||||||
|
heif: FileType.IMAGE,
|
||||||
|
jfif: FileType.IMAGE,
|
||||||
|
jpeg: FileType.IMAGE,
|
||||||
|
jpg: FileType.IMAGE,
|
||||||
|
png: FileType.IMAGE,
|
||||||
|
svg: FileType.IMAGE,
|
||||||
|
tiff: FileType.IMAGE,
|
||||||
|
webp: FileType.IMAGE,
|
||||||
|
|
||||||
|
nfo: FileType.INFORMATION,
|
||||||
|
|
||||||
|
bat: FileType.SCRIPT,
|
||||||
|
c: FileType.SCRIPT,
|
||||||
|
cmd: FileType.SCRIPT,
|
||||||
|
com: FileType.SCRIPT,
|
||||||
|
cpp: FileType.SCRIPT,
|
||||||
|
cs: FileType.SCRIPT,
|
||||||
|
css: FileType.SCRIPT,
|
||||||
|
h: FileType.SCRIPT,
|
||||||
|
hpp: FileType.SCRIPT,
|
||||||
|
java: FileType.SCRIPT,
|
||||||
|
js: FileType.SCRIPT,
|
||||||
|
py: FileType.SCRIPT,
|
||||||
|
vbs: FileType.SCRIPT,
|
||||||
|
|
||||||
|
idx: FileType.SUBTITLE,
|
||||||
|
srt: FileType.SUBTITLE,
|
||||||
|
sub: FileType.SUBTITLE,
|
||||||
|
|
||||||
|
'3gp': FileType.VIDEO,
|
||||||
|
avi: FileType.VIDEO,
|
||||||
|
flv: FileType.VIDEO,
|
||||||
|
gifv: FileType.VIDEO,
|
||||||
|
m2ts: FileType.VIDEO,
|
||||||
|
m4v: FileType.VIDEO,
|
||||||
|
mkv: FileType.VIDEO,
|
||||||
|
mov: FileType.VIDEO,
|
||||||
|
mp4: FileType.VIDEO,
|
||||||
|
mpeg: FileType.VIDEO,
|
||||||
|
mpg: FileType.VIDEO,
|
||||||
|
mts: FileType.VIDEO,
|
||||||
|
ts: FileType.VIDEO,
|
||||||
|
wmv: FileType.VIDEO,
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { DashboardDisplayMode } from './DashboardDisplayMode'
|
||||||
import { DashboardProperty } from './DashboardProperty'
|
import { DashboardProperty } from './DashboardProperty'
|
||||||
import { DashboardPropertyType } from './DashboardPropertyType'
|
import { DashboardPropertyType } from './DashboardPropertyType'
|
||||||
import { FeedState } from './FeedState'
|
import { FeedState } from './FeedState'
|
||||||
import { getFileIcon, typesMap } from './FileIcon'
|
import { FileType, extMap, typesMap } from './FileIcon'
|
||||||
import { FilterType } from './FilterType'
|
import { FilterType } from './FilterType'
|
||||||
import { HistoryKey } from './HistoryKey'
|
import { HistoryKey } from './HistoryKey'
|
||||||
import { ThemeMode } from './ThemeMode'
|
import { ThemeMode } from './ThemeMode'
|
||||||
|
@ -27,8 +27,9 @@ export {
|
||||||
DashboardProperty,
|
DashboardProperty,
|
||||||
DashboardPropertyType,
|
DashboardPropertyType,
|
||||||
FeedState,
|
FeedState,
|
||||||
getFileIcon,
|
FileType,
|
||||||
typesMap,
|
typesMap,
|
||||||
|
extMap,
|
||||||
FilterType,
|
FilterType,
|
||||||
HistoryKey,
|
HistoryKey,
|
||||||
ThemeMode,
|
ThemeMode,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import comparators, { Comparator, isObjectEqual } from './comparators'
|
||||||
import { formatDataValue, formatDataUnit, formatData } from './data'
|
import { formatDataValue, formatDataUnit, formatData } from './data'
|
||||||
import { QBIT_MAX_ETA, INFINITY_SYMBOL, formatEta, formatTimeMs, formatTimeSec, formatDuration } from './datetime'
|
import { QBIT_MAX_ETA, INFINITY_SYMBOL, formatEta, formatTimeMs, formatTimeSec, formatDuration } from './datetime'
|
||||||
import { toPrecision, formatPercent } from './number'
|
import { toPrecision, formatPercent } from './number'
|
||||||
import { basename } from './path'
|
import { basename, splitExt, getFileIcon, getExtType } from './path'
|
||||||
import { formatSpeedValue, formatSpeedUnit, formatSpeed } from './speed'
|
import { formatSpeedValue, formatSpeedUnit, formatSpeed } from './speed'
|
||||||
import { isWindows, isMac, doesCommand, openLink, downloadFile } from './system'
|
import { isWindows, isMac, doesCommand, openLink, downloadFile } from './system'
|
||||||
import { titleCase, capitalize, extractHostname, getDomainBody, splitByUrl, containsUrl, isValidUri, codeToFlag } from './text'
|
import { titleCase, capitalize, extractHostname, getDomainBody, splitByUrl, containsUrl, isValidUri, codeToFlag } from './text'
|
||||||
|
@ -27,6 +27,9 @@ export {
|
||||||
toPrecision,
|
toPrecision,
|
||||||
formatPercent,
|
formatPercent,
|
||||||
basename,
|
basename,
|
||||||
|
splitExt,
|
||||||
|
getFileIcon,
|
||||||
|
getExtType,
|
||||||
formatSpeedValue,
|
formatSpeedValue,
|
||||||
formatSpeedUnit,
|
formatSpeedUnit,
|
||||||
formatSpeed,
|
formatSpeed,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { basename, splitExt } from './path'
|
import { FileType } from '@/constants/vuetorrent'
|
||||||
|
import { basename, splitExt, getExtType, getFileIcon } from './path'
|
||||||
|
|
||||||
describe('helpers/path/basename', () => {
|
describe('helpers/path/basename', () => {
|
||||||
test('*NIX :: should return basename on files', () => {
|
test('*NIX :: should return basename on files', () => {
|
||||||
|
@ -73,3 +74,47 @@ describe('helpers/path/splitExt', () => {
|
||||||
expect(splitExt('.txt')).toEqual(['.txt', ''])
|
expect(splitExt('.txt')).toEqual(['.txt', ''])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('helpers/path/getExtType', () => {
|
||||||
|
it('should return the correct type for a known extension', () => {
|
||||||
|
expect(getExtType('txt')).toEqual(FileType.DOCUMENT)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return unknown for an unknown extension', () => {
|
||||||
|
expect(getExtType('unknown')).toBe(FileType.UNKNOWN)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return unknown for files without extension', () => {
|
||||||
|
expect(getExtType('file')).toBe(FileType.UNKNOWN)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle files starting with a dot', () => {
|
||||||
|
expect(getExtType('.hiddenfile')).toBe(FileType.UNKNOWN)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('helpers/path/getFileIcon', () => {
|
||||||
|
it('should return the correct icon for a known file type', () => {
|
||||||
|
expect(getFileIcon('file.txt')).toEqual('mdi-file-document')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return the default icon for an unknown file type', () => {
|
||||||
|
expect(getFileIcon('file.unknown')).toEqual('mdi-file')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle filenames with multiple dots correctly', () => {
|
||||||
|
expect(getFileIcon('my.file.name.txt')).toEqual('mdi-file-document')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return the default icon for files without extension', () => {
|
||||||
|
expect(getFileIcon('file')).toEqual('mdi-file')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should handle files starting with a dot', () => {
|
||||||
|
expect(getFileIcon('.hiddenfile')).toEqual('mdi-file')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should treat files with only extension as hidden', () => {
|
||||||
|
expect(getFileIcon('.txt')).toEqual('mdi-file')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { extMap, FileType, typesMap } from '@/constants/vuetorrent'
|
||||||
|
|
||||||
export function basename(path: string | null | undefined) {
|
export function basename(path: string | null | undefined) {
|
||||||
if (!path) return ''
|
if (!path) return ''
|
||||||
|
|
||||||
|
@ -17,3 +19,11 @@ export function splitExt(path: string | null | undefined): [string, string] {
|
||||||
const ext = groups.pop()!
|
const ext = groups.pop()!
|
||||||
return [groups.join('.'), ext]
|
return [groups.join('.'), ext]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getExtType(ext: string) {
|
||||||
|
return extMap[ext] || FileType.UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getFileIcon(filename: string) {
|
||||||
|
return typesMap[getExtType(splitExt(filename)[1])]
|
||||||
|
}
|
||||||
|
|
|
@ -80,6 +80,19 @@
|
||||||
"normal": "Normal",
|
"normal": "Normal",
|
||||||
"unwanted": "Unwanted"
|
"unwanted": "Unwanted"
|
||||||
},
|
},
|
||||||
|
"file_type": {
|
||||||
|
"archive": "Archives",
|
||||||
|
"audio": "Audio",
|
||||||
|
"book": "Books",
|
||||||
|
"document": "Documents",
|
||||||
|
"executable": "Executables",
|
||||||
|
"image": "Images",
|
||||||
|
"information": "Information",
|
||||||
|
"script": "Scripts",
|
||||||
|
"subtitle": "Subtitles",
|
||||||
|
"unknown": "Unknown",
|
||||||
|
"video": "Video"
|
||||||
|
},
|
||||||
"filter_type": {
|
"filter_type": {
|
||||||
"conjunctive": "Conjunctive filtering (AND)",
|
"conjunctive": "Conjunctive filtering (AND)",
|
||||||
"disjunctive": "Disjunctive filtering (OR)"
|
"disjunctive": "Disjunctive filtering (OR)"
|
||||||
|
|
Loading…
Add table
Reference in a new issue