mirror of
https://github.com/pionxzh/chatgpt-exporter.git
synced 2026-07-23 09:00:51 -05:00
feat: include project name in export all zip filenames
When exporting conversations from a project, the zip filename becomes
chatgpt-export-{format}-project-{normalized-name}.zip instead of the
generic chatgpt-export-{format}.zip.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import { KEY_TIMESTAMP_24H, KEY_TIMESTAMP_ENABLED, KEY_TIMESTAMP_HTML, baseUrl }
|
||||
import i18n from '../i18n'
|
||||
import { checkIfConversationStarted, getUserAvatar } from '../page'
|
||||
import templateHtml from '../template.html?raw'
|
||||
import { downloadFile, getFileNameWithFormat } from '../utils/download'
|
||||
import { buildZipFileName, downloadFile, getFileNameWithFormat } from '../utils/download'
|
||||
import { fromMarkdown, toHtml } from '../utils/markdown'
|
||||
import { ScriptStorage } from '../utils/storage'
|
||||
import { standardizeLineBreaks } from '../utils/text'
|
||||
@@ -31,7 +31,7 @@ export async function exportToHtml(fileNameFormat: string, metaList: ExportMeta[
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exportAllToHtml(fileNameFormat: string, apiConversations: ApiConversationWithId[], metaList?: ExportMeta[]) {
|
||||
export async function exportAllToHtml(fileNameFormat: string, apiConversations: ApiConversationWithId[], metaList?: ExportMeta[], projectName?: string) {
|
||||
const userAvatar = await getUserAvatar()
|
||||
|
||||
const zip = new JSZip()
|
||||
@@ -63,7 +63,7 @@ export async function exportAllToHtml(fileNameFormat: string, apiConversations:
|
||||
level: 9,
|
||||
},
|
||||
})
|
||||
downloadFile('chatgpt-export-html.zip', 'application/zip', blob)
|
||||
downloadFile(buildZipFileName('html', projectName), 'application/zip', blob)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3,8 +3,9 @@ import { fetchConversation, getCurrentChatId, processConversation } from '../api
|
||||
import i18n from '../i18n'
|
||||
import { checkIfConversationStarted } from '../page'
|
||||
import { convertToOoba, convertToTavern } from '../utils/conversion'
|
||||
import { downloadFile, getFileNameWithFormat } from '../utils/download'
|
||||
import { buildZipFileName, downloadFile, getFileNameWithFormat, normalizeProjectName } from '../utils/download'
|
||||
import type { ApiConversationWithId } from '../api'
|
||||
import type { ExportMeta } from '../ui/SettingContext'
|
||||
|
||||
export async function exportToJson(fileNameFormat: string) {
|
||||
if (!checkIfConversationStarted()) {
|
||||
@@ -60,14 +61,17 @@ export async function exportToOoba(fileNameFormat: string) {
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exportAllToOfficialJson(_fileNameFormat: string, apiConversations: ApiConversationWithId[]) {
|
||||
export async function exportAllToOfficialJson(_fileNameFormat: string, apiConversations: ApiConversationWithId[], _metaList?: ExportMeta[], projectName?: string) {
|
||||
const content = conversationToJson(apiConversations)
|
||||
downloadFile('chatgpt-export.json', 'application/json', content)
|
||||
const baseName = projectName
|
||||
? `chatgpt-export-project-${normalizeProjectName(projectName)}`
|
||||
: 'chatgpt-export'
|
||||
downloadFile(`${baseName}.json`, 'application/json', content)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exportAllToJson(fileNameFormat: string, apiConversations: ApiConversationWithId[]) {
|
||||
export async function exportAllToJson(fileNameFormat: string, apiConversations: ApiConversationWithId[], _metaList?: ExportMeta[], projectName?: string) {
|
||||
const zip = new JSZip()
|
||||
const filenameMap = new Map<string, number>()
|
||||
const conversations = apiConversations.map(x => ({
|
||||
@@ -100,7 +104,7 @@ export async function exportAllToJson(fileNameFormat: string, apiConversations:
|
||||
level: 9,
|
||||
},
|
||||
})
|
||||
downloadFile('chatgpt-export-json.zip', 'application/zip', blob)
|
||||
downloadFile(buildZipFileName('json', projectName), 'application/zip', blob)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { fetchConversation, getCurrentChatId, processConversation } from '../api
|
||||
import { KEY_TIMESTAMP_24H, KEY_TIMESTAMP_ENABLED, KEY_TIMESTAMP_MARKDOWN, baseUrl } from '../constants'
|
||||
import i18n from '../i18n'
|
||||
import { checkIfConversationStarted } from '../page'
|
||||
import { downloadFile, getFileNameWithFormat } from '../utils/download'
|
||||
import { buildZipFileName, downloadFile, getFileNameWithFormat } from '../utils/download'
|
||||
import { fromMarkdown, toMarkdown } from '../utils/markdown'
|
||||
import { ScriptStorage } from '../utils/storage'
|
||||
import { standardizeLineBreaks } from '../utils/text'
|
||||
@@ -28,7 +28,7 @@ export async function exportToMarkdown(fileNameFormat: string, metaList: ExportM
|
||||
return true
|
||||
}
|
||||
|
||||
export async function exportAllToMarkdown(fileNameFormat: string, apiConversations: ApiConversationWithId[], metaList?: ExportMeta[]) {
|
||||
export async function exportAllToMarkdown(fileNameFormat: string, apiConversations: ApiConversationWithId[], metaList?: ExportMeta[], projectName?: string) {
|
||||
const zip = new JSZip()
|
||||
const filenameMap = new Map<string, number>()
|
||||
const conversations = apiConversations.map(x => processConversation(x))
|
||||
@@ -58,7 +58,7 @@ export async function exportAllToMarkdown(fileNameFormat: string, apiConversatio
|
||||
level: 9,
|
||||
},
|
||||
})
|
||||
downloadFile('chatgpt-export-markdown.zip', 'application/zip', blob)
|
||||
downloadFile(buildZipFileName('markdown', projectName), 'application/zip', blob)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -269,10 +269,10 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
|
||||
const off = requestQueue.on('done', (results) => {
|
||||
setProcessing(false)
|
||||
const callback = exportAllOptions.find(o => o.label === exportType)?.callback
|
||||
if (callback) callback(format, results, metaList)
|
||||
if (callback) callback(format, results, metaList, selectedProject?.display.name)
|
||||
})
|
||||
return () => off()
|
||||
}, [requestQueue, exportAllOptions, exportType, format, metaList])
|
||||
}, [requestQueue, exportAllOptions, exportType, format, metaList, selectedProject])
|
||||
|
||||
useEffect(() => {
|
||||
const off = archiveQueue.on('done', () => {
|
||||
@@ -314,7 +314,7 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
|
||||
|
||||
const results = localConversations.filter(c => selected.some(s => s.id === c.id))
|
||||
const callback = exportAllOptions.find(o => o.label === exportType)?.callback
|
||||
if (callback) callback(format, results, metaList)
|
||||
if (callback) callback(format, results, metaList, selectedProject?.display.name)
|
||||
}, [
|
||||
disabled,
|
||||
selected,
|
||||
@@ -323,6 +323,7 @@ const DialogContent: FC<DialogContentProps> = ({ format }) => {
|
||||
exportType,
|
||||
format,
|
||||
metaList,
|
||||
selectedProject,
|
||||
])
|
||||
|
||||
const exportAll = useMemo(() => {
|
||||
|
||||
@@ -21,6 +21,20 @@ export function downloadUrl(filename: string, url: string) {
|
||||
document.body.removeChild(a)
|
||||
}
|
||||
|
||||
export function normalizeProjectName(projectName: string) {
|
||||
return projectName
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/^-+|-+$/g, '')
|
||||
}
|
||||
|
||||
export function buildZipFileName(format: string, projectName?: string) {
|
||||
if (projectName) {
|
||||
return `chatgpt-export-${format}-project-${normalizeProjectName(projectName)}.zip`
|
||||
}
|
||||
return `chatgpt-export-${format}.zip`
|
||||
}
|
||||
|
||||
export function getFileNameWithFormat(format: string, ext: string, {
|
||||
title = document.title,
|
||||
// chatId will be empty when exporting all conversations
|
||||
|
||||
Reference in New Issue
Block a user