|
|
@@ -769,6 +769,22 @@
|
|
|
params.set('imagePath', normalizeMediaUrl(ipMerged) || ipMerged);
|
|
|
}
|
|
|
/**
|
|
|
+ * 与 App utils/shareVideoPrecache.js 一致:无 shareVideoCk 时从页面解析首条 https .mp4,写入唤起链接,
|
|
|
+ * 便于 App 端 downloadFile 预缓存并与 hash 对齐后优先本地播放。
|
|
|
+ */
|
|
|
+ try {
|
|
|
+ var ckPrev = params.get('shareVideoCk');
|
|
|
+ if (!ckPrev || String(ckPrev).trim() === '') {
|
|
|
+ var pvid = pickFirstHttpsMp4ForShareVideoPrecache();
|
|
|
+ if (pvid) {
|
|
|
+ var hck = hashShareVideoRemoteUrl(pvid);
|
|
|
+ if (hck) {
|
|
|
+ params.set('shareVideoCk', hck);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (eShareCk) {}
|
|
|
+ /**
|
|
|
* App 内无分享 H5 写入的 newdetailsList;若沿用浏览器 URL 里的 fromHomeFeed=1,
|
|
|
* 详情会走「首页种子」分支并禁止 recommend,表现为仅一条、下滑无更多作品。
|
|
|
*/
|
|
|
@@ -896,6 +912,7 @@
|
|
|
}
|
|
|
|
|
|
function tryOpenHBuilderApp() {
|
|
|
+ prefetchShareVideoBeforeAppOpen();
|
|
|
var deepLink = buildAppDeepLink();
|
|
|
|
|
|
if (typeof plus !== 'undefined' && plus.runtime) {
|
|
|
@@ -1024,7 +1041,8 @@
|
|
|
'needShowMore',
|
|
|
'fromHomeFeed',
|
|
|
'appPath',
|
|
|
- 'appPage'
|
|
|
+ 'appPage',
|
|
|
+ 'shareVideoCk'
|
|
|
];
|
|
|
|
|
|
function findShareQueryValueStart(q, paramName) {
|
|
|
@@ -1913,6 +1931,125 @@
|
|
|
return urls;
|
|
|
}
|
|
|
|
|
|
+ /** 与 App utils/shareVideoPrecache.js:canonical + hash 一致 */
|
|
|
+ function canonicalVideoUrlForPrecacheKey(url) {
|
|
|
+ var s = String(url == null ? '' : url).trim();
|
|
|
+ if (!s) return '';
|
|
|
+ try {
|
|
|
+ var u = new URL(s);
|
|
|
+ return (u.origin + u.pathname).toLowerCase();
|
|
|
+ } catch (eCan) {
|
|
|
+ return String(s.split('?')[0] || '')
|
|
|
+ .trim()
|
|
|
+ .toLowerCase();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function hashShareVideoRemoteUrl(url) {
|
|
|
+ var c = canonicalVideoUrlForPrecacheKey(url);
|
|
|
+ if (!c) return '';
|
|
|
+ var h = 5381;
|
|
|
+ for (var i = 0; i < c.length; i++) {
|
|
|
+ h = ((h << 5) + h + c.charCodeAt(i)) >>> 0;
|
|
|
+ }
|
|
|
+ var h2 = 52711;
|
|
|
+ for (var j = c.length - 1; j >= 0; j--) {
|
|
|
+ h2 = (h2 * 33 + c.charCodeAt(j)) >>> 0;
|
|
|
+ }
|
|
|
+ return (h >>> 0).toString(16) + '_' + (h2 >>> 0).toString(16) + '_' + c.length;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 唤起 App 前解析首条可播 https .mp4(与详情 DomVideoPlayer 主片同源),供 shareVideoCk 与预取。
|
|
|
+ */
|
|
|
+ function pickFirstHttpsMp4ForShareVideoPrecache() {
|
|
|
+ var seen = [];
|
|
|
+ function trySeg(u) {
|
|
|
+ u = normalizeMediaUrl(String(u || '').trim());
|
|
|
+ if (!u || seen.indexOf(u) >= 0) return '';
|
|
|
+ seen.push(u);
|
|
|
+ var play = getMp4PlaybackUrl(u);
|
|
|
+ if (!play || !/^https:\/\//i.test(play)) return '';
|
|
|
+ if (!isMp4VideoUrl(play)) return '';
|
|
|
+ return play;
|
|
|
+ }
|
|
|
+ var itemObj = parseOptionsItem();
|
|
|
+ if (itemObj) {
|
|
|
+ if (Array.isArray(itemObj.imageList)) {
|
|
|
+ for (var ii = 0; ii < itemObj.imageList.length; ii++) {
|
|
|
+ var t0 = trySeg(itemObj.imageList[ii]);
|
|
|
+ if (t0) return t0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (itemObj.imagePath) {
|
|
|
+ var ips = String(itemObj.imagePath).split(/,(?=https?:\/\/)/);
|
|
|
+ if (ips.length <= 1) ips = String(itemObj.imagePath).split(',');
|
|
|
+ for (var jj = 0; jj < ips.length; jj++) {
|
|
|
+ var t1 = trySeg(ips[jj]);
|
|
|
+ if (t1) return t1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var itBlob = parseShareDynamicItemBlob();
|
|
|
+ if (itBlob && itBlob !== itemObj) {
|
|
|
+ if (Array.isArray(itBlob.imageList)) {
|
|
|
+ for (var aa = 0; aa < itBlob.imageList.length; aa++) {
|
|
|
+ var t2 = trySeg(itBlob.imageList[aa]);
|
|
|
+ if (t2) return t2;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (itBlob.imagePath) {
|
|
|
+ var ips2 = String(itBlob.imagePath).split(/,(?=https?:\/\/)/);
|
|
|
+ if (ips2.length <= 1) ips2 = String(itBlob.imagePath).split(',');
|
|
|
+ for (var bb = 0; bb < ips2.length; bb++) {
|
|
|
+ var t3 = trySeg(ips2[bb]);
|
|
|
+ if (t3) return t3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var carousel = collectImageUrlsFromUrl();
|
|
|
+ for (var kk = 0; kk < carousel.length; kk++) {
|
|
|
+ var t4 = trySeg(carousel[kk]);
|
|
|
+ if (t4) return t4;
|
|
|
+ }
|
|
|
+ var topIp = getMergedParam('imagePath');
|
|
|
+ if (topIp) {
|
|
|
+ var segs2 = normalizeMediaUrl(topIp).split(/,(?=https?:\/\/)/);
|
|
|
+ if (segs2.length <= 1) segs2 = String(topIp).split(',');
|
|
|
+ for (var mm = 0; mm < segs2.length; mm++) {
|
|
|
+ var t5 = trySeg(segs2[mm]);
|
|
|
+ if (t5) return t5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 唤醒 App 前尽力拉取视频(Cache API / prefetch / fetch);与 App 沙箱缓存独立,仅减轻部分环境下的首包 */
|
|
|
+ function prefetchShareVideoBeforeAppOpen() {
|
|
|
+ try {
|
|
|
+ var u = pickFirstHttpsMp4ForShareVideoPrecache();
|
|
|
+ if (!u) return;
|
|
|
+ if ('caches' in window && window.caches && window.caches.open) {
|
|
|
+ window.caches
|
|
|
+ .open('shopro-share-dynamic-video-v1')
|
|
|
+ .then(function (cache) {
|
|
|
+ return cache.add(u);
|
|
|
+ })
|
|
|
+ .catch(function () {});
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ var lnk = document.createElement('link');
|
|
|
+ lnk.rel = 'prefetch';
|
|
|
+ lnk.as = 'video';
|
|
|
+ lnk.href = u;
|
|
|
+ document.head.appendChild(lnk);
|
|
|
+ } catch (eL) {}
|
|
|
+ if (typeof fetch === 'function') {
|
|
|
+ fetch(u, { method: 'GET', mode: 'cors', cache: 'force-cache' }).catch(function () {});
|
|
|
+ }
|
|
|
+ } catch (eP) {}
|
|
|
+ }
|
|
|
+
|
|
|
var heroI = 0;
|
|
|
var heroTimer = null;
|
|
|
var dynHeroSwipeInited = false;
|