diff --git a/src/renderer/src/locales/lang/en_US/pages/setting.ts b/src/renderer/src/locales/lang/en_US/pages/setting.ts index 03bbcdede..090cc5ef0 100644 --- a/src/renderer/src/locales/lang/en_US/pages/setting.ts +++ b/src/renderer/src/locales/lang/en_US/pages/setting.ts @@ -285,6 +285,12 @@ export default { title: 'Source Tool [Hjdhnx United]', template: 'template', templateTip: 'select one default template to edit', + reqHeaderTitle: 'Request Header', + reqBodyTitle: 'Request Body', + placeholder: { + reqHeader: '{ "User-Agent": "Mozilla/5.0 zyplayer" }', + reqBody: '{ "key": "01b9b7" }', + }, rule: { pdfa: 'Pdfa', pdfh: 'Pdfh', @@ -307,6 +313,7 @@ export default { initAuto: 'Auto', classify: 'Classify', source: 'Source', + obtain: 'Obtain', home: 'Home', list: 'List', detail: 'Detail', @@ -332,7 +339,11 @@ export default { dialog: { player: { title: 'PlayTest' + }, + request: { + title: 'RequestParameters', + cancel: 'Reset' } } } -} \ No newline at end of file +} diff --git a/src/renderer/src/locales/lang/zh_CN/pages/setting.ts b/src/renderer/src/locales/lang/zh_CN/pages/setting.ts index a5b1c8136..4af042227 100644 --- a/src/renderer/src/locales/lang/zh_CN/pages/setting.ts +++ b/src/renderer/src/locales/lang/zh_CN/pages/setting.ts @@ -285,6 +285,12 @@ export default { title: '写源工具 [道长联名]', template: '模板', templateTip: '选择一个要编辑的默认模板', + reqHeaderTitle: '请求头', + reqBodyTitle: '请求体', + placeholder: { + reqHeader: '{ "User-Agent": "Mozilla/5.0 zyplayer" }', + reqBody: '{ "key": "01b9b7" }', + }, rule: { pdfa: '列表', pdfh: '节点', @@ -306,6 +312,7 @@ export default { initManual: '手动', initAuto: '自动', source: '源代码', + obtain: '获取', classify: '分类', home: '首页', list: '列表', @@ -332,7 +339,11 @@ export default { dialog: { player: { title: '播放测试' + }, + request: { + title: '请求参数', + cancel: '重置' } } } -} \ No newline at end of file +} diff --git a/src/renderer/src/pages/setting/tool/EditSource.vue b/src/renderer/src/pages/setting/tool/EditSource.vue index b8c5a2f47..c1493a1ca 100644 --- a/src/renderer/src/pages/setting/tool/EditSource.vue +++ b/src/renderer/src/pages/setting/tool/EditSource.vue @@ -6,6 +6,10 @@
+
+ + {{ $t('pages.setting.editSource.template') }} +
{{ $t('pages.setting.editSource.import') }} @@ -34,6 +38,14 @@ {{ $t('pages.setting.editSource.help') }}
+ + +

{{ $t('pages.setting.editSource.templateTip') }}

+ + + +
@@ -42,25 +54,46 @@
-
- {{ - $t('pages.setting.editSource.template') }} - -

{{ $t('pages.setting.editSource.templateTip') }}

- - - -
-
- + + - +
+ +
+ +
+
+ +
+

{{ $t('pages.setting.editSource.reqHeaderTitle') }}

+ +
+
+

{{ $t('pages.setting.editSource.reqBodyTitle') }}

+ + + + +
+
@@ -228,7 +261,7 @@ import JSON5 from "json5"; import { computed, nextTick, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'; import { useRouter } from 'vue-router'; import { MessagePlugin } from 'tdesign-vue-next'; -import { BugIcon, DeleteIcon, FileDownloadIcon, FileExportIcon, FileImportIcon, HelpRectangleIcon, InternetIcon, GestureClickIcon } from 'tdesign-icons-vue-next'; +import { BugIcon, DeleteIcon, ExtensionIcon, FileDownloadIcon, FileExportIcon, FileImportIcon, HelpRectangleIcon, InternetIcon, GestureClickIcon, TransformIcon } from 'tdesign-icons-vue-next'; import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'; import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; @@ -273,6 +306,13 @@ let form = ref({ template: 'mxpro', url: '', nav: 'debug', + req: { + method: 'GET', + header: '', + body: '', + url: '', + contentType: 'application/json' + }, detail: { ids: '' }, @@ -315,7 +355,8 @@ let form = ref({ const isVisible = reactive({ template: false, player: false, - help: false + help: false, + reqParam: false }); const formDialog = reactive({ @@ -361,6 +402,44 @@ interface EditorConfig { wordWrap: WordWrapOptions; } +const reqMethods = [ + { + label: 'GET', + value: 'GET', + }, + { + label: 'POST', + value: 'POST', + }, + { + label: 'DELETE', + value: 'DELETE', + }, + { + label: 'PUT', + value: 'PUT', + }, + { + label: 'OPTIONS', + value: 'OPTIONS', + }, + { + label: 'HEAD', + value: 'HEAD', + } +]; + +const reqContentTypes = [ + { + label: 'application/json', + value: 'application/json', + }, + { + label: 'application/x-www-form-urlencoded', + value: 'application/x-www-form-urlencoded', + }, +]; + const config = reactive({ theme: systemTheme.value === 'light' ? 'vs' : 'vs-dark', language: 'javascript', @@ -676,6 +755,13 @@ const performAction = async (type, requestData = {}) => { }; const res: any = await t3Work({ type, data: requestData }); form.value.content.debug = res.data as string; + switch (type) { + case 'play': + if (res.data?.url) form.value.player.url = res.data.url; + break; + case 'detail': + break; + } form.value.action = type; changeNav('debug', type); MessagePlugin.success(t('pages.setting.data.success')); @@ -787,12 +873,43 @@ const actionPlayer = async (url = "") => { }; const getSource = async () => { - const url = form.value.url; - if (url) { - const res = await getConfig(url); - form.value.content.source = res; + let { url, method, header, body, contentType } = form.value.req; + header = header ? header : '{}'; + body = body ? body : '{}'; + + if (!url) return; + + try { + const parsedHeader = JSON5.parse(header); + let parsedBody = JSON5.parse(body); + + if (method !== 'GET' && parsedBody) { + parsedHeader['Content-Type'] = contentType; + if (contentType === 'application/x-www-form-urlencoded') { + parsedBody instanceof URLSearchParams + ? parsedBody + : (parsedBody = new URLSearchParams(parsedBody)); + } + } + + const response = await getConfig(url, method, parsedHeader, parsedBody); + + form.value.content.source = response; changeNav('source', 'html'); - }; + } catch (error) { + console.error('Error parsing header or body:', error); + } +}; + +const showReqParamDialog = () => { + isVisible.reqParam = true; +}; + +const reqCancel = (e) => { + form.value.req.header = ''; + form.value.req.body = ''; + form.value.req.contentType = 'application/json'; + e.preventDefault(); }; const showTemplateDialog = () => { @@ -979,6 +1096,34 @@ const proxyEvent = async () => { :deep(.t-input-adornment) { width: 100%; + + .input-container { + width: inherit; + background-color: var(--td-bg-content-input) !important; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + + .method { + margin-right: 5px; + width: 24px; + height: 24px; + border-radius: var(--td-radius-default); + background-color: var(--td-bg-color-component); + display: flex; + flex-direction: row; + align-content: center; + align-items: center; + justify-content: center; + cursor: pointer; + } + + .contentType { + margin-bottom: 5px; + } + } } } @@ -1185,7 +1330,8 @@ const proxyEvent = async () => { :deep(.t-input), :deep(.t-input-number__increase), :deep(.t-input-number__decrease), -:deep(.t-input-adornment__text) { +:deep(.t-input-adornment__text), +:deep(.t-textarea__inner) { background-color: var(--td-bg-content-input) !important; border-color: transparent; box-shadow: none; diff --git a/src/renderer/src/utils/tool.ts b/src/renderer/src/utils/tool.ts index cd6ae51e1..04974a7cd 100644 --- a/src/renderer/src/utils/tool.ts +++ b/src/renderer/src/utils/tool.ts @@ -4,20 +4,36 @@ import ip from 'ip'; axios.defaults.withCredentials = true; //让ajax携带cookie -const getConfig = async (url, header = {}) => { +const getConfig = async (url: string, method = 'GET', headers = {}, body = {}) => { try { - let res; - if( header ) res = await axios.get(url, {headers: { ...header }}); - else res = await axios.get(url); - let response; + const customHeaders = { + 'Cookie': 'custom-cookie', + 'User-Agent': 'custom-ua', + 'Referer': 'custom-referer', + }; + for (const [originalHeader, customHeader] of Object.entries(customHeaders)) { + if (headers.hasOwnProperty(originalHeader)) { + headers[customHeader] = headers[originalHeader]; + delete headers[originalHeader]; + } + } + + const response = await axios({ + method, + url, + data: method !== 'GET' ? body : undefined, + headers: headers || undefined + }) + + let responseData; try { - response = JSON5.parse(res.data); - } catch (err) { - response = res.data; + responseData = JSON5.parse(response.data); + } catch (parseError) { + responseData = response.data; } - return response || false; + return responseData || false; } catch (err) { throw err; } @@ -25,9 +41,9 @@ const getConfig = async (url, header = {}) => { // 判断媒体类型 const checkMediaType = async (url: string): Promise => { - const supportedFormats: string[] = ['mp4', 'mkv', 'flv', 'm3u8', 'avi']; + const supportedFormats: string[] = ['mp4', 'mkv', 'flv', 'm3u8', 'avi', 'magnet']; - if (url.startsWith('http')) { + if (url.startsWith('http') || url.startsWith('magnet')) { const fileType = supportedFormats.find(format => url.includes(format)); if (fileType) { return fileType; @@ -92,7 +108,7 @@ const checkLiveM3U8 = async(url: string): Promise =>{ try { const res = await axios.get(url); const m3u8Content = res.data; - + const isLiveStream = !( m3u8Content.indexOf('#EXT-X-ENDLIST') !== -1 || (m3u8Content.indexOf('#EXT-X-PLAYLIST-TYPE') !== -1 && @@ -100,7 +116,7 @@ const checkLiveM3U8 = async(url: string): Promise =>{ (m3u8Content.indexOf('#EXT-X-MEDIA-SEQUENCE') !== -1 && parseInt(m3u8Content.match(/#EXT-X-MEDIA-SEQUENCE:(\d+)/)[1]) === 0) ); - + return isLiveStream; } catch (err) { return false; @@ -116,4 +132,4 @@ const copyToClipboardApi = async (text: string): Promise => { } }; -export { getConfig, getMeadiaType, checkMediaType, checkUrlIpv6, checkLiveM3U8, copyToClipboardApi } \ No newline at end of file +export { getConfig, getMeadiaType, checkMediaType, checkUrlIpv6, checkLiveM3U8, copyToClipboardApi }