Setting the file. One moment.
Product Video Extract · Rp Source Wordpress · wix/skills · Skills Docs
ContentsBack to the top of the page 39.41
PLUGIN READ PLANS
lib/ product-video-extract.js
JavaScript · 116 lines · 5 KB
);
14 const path = require ( 'node:path' );
15 const { phpUnserialize } = require ( './wp-redirect-sources.js' );
16
17 const SOURCES_PATH = path. join (__dirname, '..' , 'product-video-sources.json' );
18
19 function loadVideoSources ( file = SOURCES_PATH ) {
20 const doc = JSON . parse (fs. readFileSync (file, 'utf8' ));
21 if (doc.schemaVersion !== 1 || ! Array. isArray (doc.sources)) throw new Error ( `${ file }: expected schemaVersion 1 with sources[]` );
22 for ( const [ index , source ] of doc.sources. entries ()) {
23 if ( ! source || typeof source.key !== 'string' || ! source.key || typeof source.origin !== 'string' || ! source.origin) {
24 throw new Error ( `${ file }: sources[${ index }] needs key and origin` );
25 }
26 if ( ! [ 'object' , 'url-list' ]. includes (source.shape)) throw new Error ( `${ file }: sources[${ index }].shape must be object or url-list` );
27 if (source.shape === 'object' && ( typeof source.url !== 'string' || ! source.url)) throw new Error ( `${ file }: sources[${ index }] shape object needs url` );
28 }
29 return doc;
30 }
31
32 function decode ( value ) {
33 if ( typeof value !== 'string' ) return value;
34 const text = value. trim ();
35 if ( / ^ (a | s): \d + :/ . test (text)) {
36 try { return phpUnserialize (text); } catch { return value; }
37 }
38 if (text. startsWith ( '{' ) || text. startsWith ( '[' )) {
39 try { return JSON . parse (text); } catch { return value; }
40 }
41 return value;
42 }
43
44 function hostMatches ( host , domains ) {
45 return domains. some (( domain ) => host === domain || host. endsWith ( `.${ domain }` ));
46 }
47
48 function classifyVideoUrl ( url , knowledge ) {
49 let parsed;
50 try { parsed = new URL (url); } catch { return 'other' ; }
51 if ( ! [ 'http:' , 'https:' ]. includes (parsed.protocol)) return 'other' ;
52 const host = parsed.hostname. toLowerCase ();
53 for ( const [ kind , domains ] of Object. entries (knowledge.embedHosts || {})) {
54 if ( hostMatches (host, domains)) return kind;
55 }
56 const extension = path. extname ( decodeURIComponent (parsed.pathname)). slice ( 1 ). toLowerCase ();
57 return (knowledge.fileExtensions || []). includes (extension) ? 'file' : 'other' ;
58 }
59
60 function urlsOf ( source , value ) {
61 const decoded = decode (value);
62 if (source.shape === 'url-list' ) {
63 const list = Array. isArray (decoded) ? decoded : (decoded && typeof decoded === 'object' ? Object. values (decoded) : [decoded]);
64 return list. filter (( entry ) => typeof entry === 'string' );
65 }
66 if (decoded && typeof decoded === 'object' && ! Array. isArray (decoded)) {
67 const url = decoded[source.url];
68 return typeof url === 'string' ? [url] : [];
69 }
70 return [];
71 }
72
73 function recordOf ( row ) {
74 return row && typeof row === 'object' && row.record && typeof row.record === 'object' ? row.record : row;
75 }
76
77 // One product -> [{ url, kind, origin, metaKey }], in source order, deduplicated by URL.
78 function extractProductVideos ( product , knowledge = loadVideoSources ()) {
79 const record = recordOf (product);
80 const meta = Array. isArray (record?.meta_data) ? record.meta_data : [];
81 const out = [];
82 const seen = new Set ();
83 for ( const source of knowledge.sources) {
84 for ( const entry of meta. filter (( item ) => item && item.key === source.key)) {
85 for ( const raw of urlsOf (source, entry.value)) {
86 const url = raw. trim ();
87 if ( ! url || seen. has (url)) continue ;
88 seen. add (url);
89 out. push ({ url, kind: classifyVideoUrl (url, knowledge), origin: source.origin, metaKey: source.key });
90 }
91 }
92 }
93 return out;
94 }
95
96 // Products -> the deterministic plan the importer and the completion report share.
97 function planProductVideos ( products , knowledge = loadVideoSources ()) {
98 const attach = [];
99 const manual = [];
100 for ( const row of products) {
101 const record = recordOf (row);
102 if ( ! record || record.id === undefined || record.id === null ) continue ;
103 const videos = extractProductVideos (record, knowledge);
104 if ( ! videos. length ) continue ;
105 const productSourceId = String (record.id);
106 const name = typeof record.name === 'string' ? record.name : null ;
107 const files = videos. filter (( video ) => video.kind === 'file' );
108 if (files. length ) attach. push ({ productSourceId, name, videos: files. map (({ url , origin }) => ({ url, origin })) });
109 for ( const video of videos. filter (( entry ) => entry.kind !== 'file' )) {
110 manual. push ({ productSourceId, name, url: video.url, kind: video.kind, origin: video.origin });
111 }
112 }
113 return { attach, manual };
114 }
115
116 module . exports = { SOURCES_PATH, loadVideoSources, classifyVideoUrl, extractProductVideos, planProductVideos };