feat: add support to audio and video API responses (#3044)

This commit is contained in:
Liyas Thomas
2023-05-25 01:46:14 +05:30
committed by GitHub
parent 9dbdef9286
commit ddaec1b9ac
6 changed files with 196 additions and 0 deletions

View File

@@ -432,6 +432,7 @@
"view_my_links": "View my links"
},
"response": {
"audio": "Audio",
"body": "Response Body",
"filter_response_body": "Filter JSON response body (uses JSONPath syntax)",
"headers": "Headers",
@@ -445,6 +446,7 @@
"status": "Status",
"time": "Time",
"title": "Response",
"video": "Video",
"waiting_for_connection": "waiting for connection",
"xml": "XML"
},

View File

@@ -0,0 +1,79 @@
<template>
<div class="flex flex-col flex-1">
<div
class="sticky z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight top-lowerSecondaryStickyFold"
>
<label class="font-semibold truncate text-secondaryLight">
{{ t("response.body") }}
</label>
<div class="flex">
<HoppButtonSecondary
v-if="response.body"
v-tippy="{ theme: 'tooltip', allowHTML: true }"
:title="`${t(
'action.download_file'
)} <kbd>${getSpecialKey()}</kbd><kbd>J</kbd>`"
:icon="downloadIcon"
@click="downloadResponse"
/>
</div>
</div>
<div class="flex flex-1 items-center justify-center overflow-auto">
<audio controls :src="audiosrc"></audio>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue"
import { useI18n } from "@composables/i18n"
import { useDownloadResponse } from "@composables/lens-actions"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { defineActionHandler } from "~/helpers/actions"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import { flow, pipe } from "fp-ts/function"
import * as S from "fp-ts/string"
import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option"
import { objFieldMatches } from "~/helpers/functional/object"
const t = useI18n()
const props = defineProps<{
response: HoppRESTResponse & {
type: "success" | "fail"
}
}>()
const audiosrc = computed(() =>
URL.createObjectURL(
new Blob([props.response.body], {
type: "audio/mp3",
})
)
)
const responseType = computed(() =>
pipe(
props.response,
O.fromPredicate(objFieldMatches("type", ["fail", "success"] as const)),
O.chain(
// Try getting content-type
flow(
(res) => res.headers,
A.findFirst((h) => h.key.toLowerCase() === "content-type"),
O.map(flow((h) => h.value, S.split(";"), RNEA.head, S.toLowerCase))
)
),
O.getOrElse(() => "text/plain")
)
)
const { downloadIcon, downloadResponse } = useDownloadResponse(
responseType.value,
computed(() => props.response.body)
)
defineActionHandler("response.file.download", () => downloadResponse())
</script>

View File

@@ -0,0 +1,79 @@
<template>
<div class="flex flex-col flex-1">
<div
class="sticky z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight top-lowerSecondaryStickyFold"
>
<label class="font-semibold truncate text-secondaryLight">
{{ t("response.body") }}
</label>
<div class="flex">
<HoppButtonSecondary
v-if="response.body"
v-tippy="{ theme: 'tooltip', allowHTML: true }"
:title="`${t(
'action.download_file'
)} <kbd>${getSpecialKey()}</kbd><kbd>J</kbd>`"
:icon="downloadIcon"
@click="downloadResponse"
/>
</div>
</div>
<div class="flex flex-1 items-center justify-center overflow-auto">
<video controls :src="videosrc"></video>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue"
import { useI18n } from "@composables/i18n"
import { useDownloadResponse } from "@composables/lens-actions"
import { HoppRESTResponse } from "~/helpers/types/HoppRESTResponse"
import { defineActionHandler } from "~/helpers/actions"
import { getPlatformSpecialKey as getSpecialKey } from "~/helpers/platformutils"
import { flow, pipe } from "fp-ts/function"
import * as S from "fp-ts/string"
import * as RNEA from "fp-ts/ReadonlyNonEmptyArray"
import * as A from "fp-ts/Array"
import * as O from "fp-ts/Option"
import { objFieldMatches } from "~/helpers/functional/object"
const t = useI18n()
const props = defineProps<{
response: HoppRESTResponse & {
type: "success" | "fail"
}
}>()
const videosrc = computed(() =>
URL.createObjectURL(
new Blob([props.response.body], {
type: "video/mp4",
})
)
)
const responseType = computed(() =>
pipe(
props.response,
O.fromPredicate(objFieldMatches("type", ["fail", "success"] as const)),
O.chain(
// Try getting content-type
flow(
(res) => res.headers,
A.findFirst((h) => h.key.toLowerCase() === "content-type"),
O.map(flow((h) => h.value, S.split(";"), RNEA.head, S.toLowerCase))
)
),
O.getOrElse(() => "text/plain")
)
)
const { downloadIcon, downloadResponse } = useDownloadResponse(
responseType.value,
computed(() => props.response.body)
)
defineActionHandler("response.file.download", () => downloadResponse())
</script>

View File

@@ -0,0 +1,16 @@
import { defineAsyncComponent } from "vue"
import { Lens } from "./lenses"
const audioLens: Lens = {
lensName: "response.audio",
isSupportedContentType: (contentType) =>
/\baudio\/(?:wav|mpeg|mp4|aac|aacp|ogg|webm|x-caf|flac|mp3|)\b/i.test(
contentType
),
renderer: "audiores",
rendererImport: defineAsyncComponent(
() => import("~/components/lenses/renderers/AudioLensRenderer.vue")
),
}
export default audioLens

View File

@@ -5,6 +5,8 @@ import imageLens from "./imageLens"
import htmlLens from "./htmlLens"
import xmlLens from "./xmlLens"
import pdfLens from "./pdfLens"
import audioLens from "./audioLens"
import videoLens from "./videoLens"
import { defineAsyncComponent } from "vue"
export type Lens = {
@@ -20,6 +22,8 @@ export const lenses: Lens[] = [
htmlLens,
xmlLens,
pdfLens,
audioLens,
videoLens,
rawLens,
]

View File

@@ -0,0 +1,16 @@
import { defineAsyncComponent } from "vue"
import { Lens } from "./lenses"
const videoLens: Lens = {
lensName: "response.video",
isSupportedContentType: (contentType) =>
/\bvideo\/(?:webm|x-m4v|quicktime|x-ms-wmv|x-flv|mpeg|x-msvideo|x-ms-asf|mp4|)\b/i.test(
contentType
),
renderer: "videores",
rendererImport: defineAsyncComponent(
() => import("~/components/lenses/renderers/VideoLensRenderer.vue")
),
}
export default videoLens