@kimjansheden/payload-video-processor 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { FC } from 'react';
2
- import { e as VideoVariantFieldConfig } from '../types-BjFcE25o.cjs';
2
+ import { f as VideoVariantFieldConfig } from '../types-DJGPSfvi.cjs';
3
3
  import 'payload';
4
4
 
5
5
  type BridgeArgs = {
@@ -1,5 +1,5 @@
1
1
  import { FC } from 'react';
2
- import { e as VideoVariantFieldConfig } from '../types-BjFcE25o.js';
2
+ import { f as VideoVariantFieldConfig } from '../types-DJGPSfvi.js';
3
3
  import 'payload';
4
4
 
5
5
  type BridgeArgs = {
@@ -1,4 +1,4 @@
1
1
  export { default as VideoField } from './VideoField.cjs';
2
2
  import 'react';
3
- import '../types-BjFcE25o.cjs';
3
+ import '../types-DJGPSfvi.cjs';
4
4
  import 'payload';
@@ -1,4 +1,4 @@
1
1
  export { default as VideoField } from './VideoField.js';
2
2
  import 'react';
3
- import '../types-BjFcE25o.js';
3
+ import '../types-DJGPSfvi.js';
4
4
  import 'payload';
package/dist/index.cjs CHANGED
@@ -651,6 +651,167 @@ var createReplaceOriginalHandler = ({ access }) => async (req) => {
651
651
  }
652
652
  };
653
653
 
654
+ // src/utils/playback.ts
655
+ var isAbsoluteUrl = (value) => value.startsWith("http://") || value.startsWith("https://") || value.startsWith("data:") || value.startsWith("blob:") || value.startsWith("//");
656
+ var readHeader = (headers, name) => {
657
+ if (!headers) {
658
+ return "";
659
+ }
660
+ if (typeof headers.get === "function") {
661
+ return headers.get(name) ?? headers.get(name.toLowerCase()) ?? "";
662
+ }
663
+ const record = headers;
664
+ const value = record[name] ?? record[name.toLowerCase()];
665
+ if (typeof value === "string") {
666
+ return value;
667
+ }
668
+ if (Array.isArray(value)) {
669
+ return typeof value[0] === "string" ? value[0] : "";
670
+ }
671
+ return "";
672
+ };
673
+ var getServerUrlFromReq = (req) => {
674
+ const serverURL = req?.payload?.config?.serverURL;
675
+ return typeof serverURL === "string" ? serverURL.trim() : "";
676
+ };
677
+ var getRequestOrigin = (req) => {
678
+ const serverURL = getServerUrlFromReq(req);
679
+ if (serverURL) {
680
+ try {
681
+ return new URL(serverURL).origin;
682
+ } catch {
683
+ }
684
+ }
685
+ const requestUrl = typeof req?.url === "string" ? req.url : "";
686
+ if (requestUrl && isAbsoluteUrl(requestUrl)) {
687
+ try {
688
+ return new URL(requestUrl).origin;
689
+ } catch {
690
+ }
691
+ }
692
+ const headers = req?.headers;
693
+ const forwardedProto = readHeader(headers, "x-forwarded-proto");
694
+ const forwardedHost = readHeader(headers, "x-forwarded-host");
695
+ const host = forwardedHost || readHeader(headers, "host");
696
+ const proto = forwardedProto || "http";
697
+ return host ? `${proto}://${host}` : "";
698
+ };
699
+ var resolvePlaybackUrl = (input, bases) => {
700
+ if (typeof input !== "string") {
701
+ return "";
702
+ }
703
+ const trimmed = input.trim();
704
+ if (!trimmed) {
705
+ return "";
706
+ }
707
+ if (isAbsoluteUrl(trimmed)) {
708
+ try {
709
+ return new URL(trimmed).toString();
710
+ } catch {
711
+ return "";
712
+ }
713
+ }
714
+ for (const base of bases) {
715
+ if (!base) {
716
+ continue;
717
+ }
718
+ try {
719
+ return new URL(trimmed, base).toString();
720
+ } catch {
721
+ }
722
+ }
723
+ return trimmed;
724
+ };
725
+ var inferVideoMimeTypeFromUrl = (url) => {
726
+ const cleanUrl = url.split("#")[0]?.split("?")[0] ?? "";
727
+ const lower = cleanUrl.toLowerCase();
728
+ if (lower.endsWith(".mp4") || lower.endsWith(".m4v") || lower.endsWith(".mov")) {
729
+ return "video/mp4";
730
+ }
731
+ if (lower.endsWith(".webm")) {
732
+ return "video/webm";
733
+ }
734
+ if (lower.endsWith(".ogv") || lower.endsWith(".ogg")) {
735
+ return "video/ogg";
736
+ }
737
+ return void 0;
738
+ };
739
+ var normaliseVideoSourceType = (mimeType, resolvedUrl) => {
740
+ const normalised = typeof mimeType === "string" ? mimeType.trim().toLowerCase() : "";
741
+ if (normalised === "video/quicktime") {
742
+ return "video/mp4";
743
+ }
744
+ if (normalised) {
745
+ return normalised;
746
+ }
747
+ return inferVideoMimeTypeFromUrl(resolvedUrl);
748
+ };
749
+ var getThumbnailCandidate = (doc) => {
750
+ const sizes = doc.sizes;
751
+ if (sizes && typeof sizes === "object") {
752
+ const sizeCandidates = ["medium", "large", "square", "thumbnail"];
753
+ for (const key of sizeCandidates) {
754
+ const entry = sizes[key];
755
+ const url = entry?.url;
756
+ if (typeof url === "string" && url.trim()) {
757
+ return url;
758
+ }
759
+ }
760
+ }
761
+ if (typeof doc.thumbnailURL === "string" && doc.thumbnailURL.trim()) {
762
+ return doc.thumbnailURL;
763
+ }
764
+ return void 0;
765
+ };
766
+ var buildPlaybackSources = ({
767
+ doc,
768
+ req
769
+ }) => {
770
+ const sources = [];
771
+ const seen = /* @__PURE__ */ new Set();
772
+ const docUrl = typeof doc.url === "string" ? doc.url.trim() : "";
773
+ const requestOrigin = getRequestOrigin(req);
774
+ const bases = [docUrl, requestOrigin].filter(Boolean);
775
+ const variants = Array.isArray(doc.variants) ? doc.variants : [];
776
+ const sortedVariants = [...variants].sort((a, b) => {
777
+ const aSize = typeof a?.size === "number" ? a.size : Number.NEGATIVE_INFINITY;
778
+ const bSize = typeof b?.size === "number" ? b.size : Number.NEGATIVE_INFINITY;
779
+ return bSize - aSize;
780
+ });
781
+ for (const variant of sortedVariants) {
782
+ const resolvedUrl = resolvePlaybackUrl(variant?.url, bases);
783
+ if (!resolvedUrl || seen.has(resolvedUrl)) {
784
+ continue;
785
+ }
786
+ seen.add(resolvedUrl);
787
+ sources.push({
788
+ preset: typeof variant?.preset === "string" ? variant.preset : void 0,
789
+ src: resolvedUrl,
790
+ type: normaliseVideoSourceType(void 0, resolvedUrl)
791
+ });
792
+ }
793
+ const resolvedOriginalUrl = resolvePlaybackUrl(doc.url, bases);
794
+ if (resolvedOriginalUrl && !seen.has(resolvedOriginalUrl)) {
795
+ sources.push({
796
+ src: resolvedOriginalUrl,
797
+ type: normaliseVideoSourceType(doc.mimeType, resolvedOriginalUrl)
798
+ });
799
+ }
800
+ return sources;
801
+ };
802
+ var buildPlaybackPosterUrl = ({
803
+ doc,
804
+ req
805
+ }) => {
806
+ const docUrl = typeof doc.url === "string" ? doc.url.trim() : "";
807
+ const requestOrigin = getRequestOrigin(req);
808
+ const bases = [docUrl, requestOrigin].filter(Boolean);
809
+ const storedPoster = typeof doc.playbackPosterUrl === "string" ? doc.playbackPosterUrl.trim() : "";
810
+ const candidate = storedPoster || getThumbnailCandidate(doc);
811
+ const resolved = resolvePlaybackUrl(candidate, bases);
812
+ return resolved || void 0;
813
+ };
814
+
654
815
  // src/ffmpeg/args.ts
655
816
  var FASTSTART_FLAGS = ["-movflags", "+faststart"];
656
817
  var CRF_FLAG = "-crf";
@@ -1091,9 +1252,39 @@ var pluginFactory = (rawOptions) => {
1091
1252
  };
1092
1253
  fields.push(controlField);
1093
1254
  }
1255
+ const existingHooks = collection.hooks ?? {};
1256
+ const existingAfterRead = Array.isArray(existingHooks.afterRead) ? existingHooks.afterRead : [];
1257
+ const hooks = {
1258
+ ...existingHooks,
1259
+ afterRead: [
1260
+ ...existingAfterRead,
1261
+ ({ doc, req }) => {
1262
+ if (!doc || typeof doc !== "object") {
1263
+ return doc;
1264
+ }
1265
+ const mimeType = typeof doc.mimeType === "string" ? doc.mimeType : "";
1266
+ if (!mimeType.startsWith("video/")) {
1267
+ return doc;
1268
+ }
1269
+ doc.playbackSources = buildPlaybackSources({
1270
+ doc,
1271
+ req
1272
+ });
1273
+ const posterUrl = buildPlaybackPosterUrl({
1274
+ doc,
1275
+ req
1276
+ });
1277
+ if (posterUrl) {
1278
+ doc.playbackPosterUrl = posterUrl;
1279
+ }
1280
+ return doc;
1281
+ }
1282
+ ]
1283
+ };
1094
1284
  return {
1095
1285
  ...collection,
1096
- fields
1286
+ fields,
1287
+ hooks
1097
1288
  };
1098
1289
  }
1099
1290
  );