@thun888/live-photo 1.0.0
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.
- package/README.md +6 -0
- package/dist/bundle.js +1 -0
- package/dist/main.css +1 -0
- package/package.json +23 -0
package/dist/bundle.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.LivePhoto=t():e.LivePhoto=t()}(self,()=>(()=>{"use strict";var e={d:(t,i)=>{for(var n in i)e.o(i,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:i[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{init:()=>r});const i="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjNjA2MDYwIiBkPSJtMTggMTMuNGwtMS45IDEuOXEtLjI3NS4yNzUtLjcuMjc1dC0uNy0uMjc1dC0uMjc1LS43dC4yNzUtLjdsMS45LTEuOWwtMS45LTEuOXEtLjI3NS0uMjc1LS4yNzUtLjd0LjI3NS0uN3QuNy0uMjc1dC43LjI3NWwxLjkgMS45bDEuOS0xLjlxLjI3NS0uMjc1LjctLjI3NXQuNy4yNzV0LjI3NS43dC0uMjc1LjdMMTkuNCAxMmwxLjkgMS45cS4yNzUuMjc1LjI3NS43dC0uMjc1Ljd0LS43LjI3NXQtLjctLjI3NXpNNyAxNUg0cS0uNDI1IDAtLjcxMi0uMjg4VDMgMTR2LTRxMC0uNDI1LjI4OC0uNzEyVDQgOWgzbDMuMy0zLjNxLjQ3NS0uNDc1IDEuMDg4LS4yMTN0LjYxMi45Mzh2MTEuMTVxMCAuNjc1LS42MTIuOTM4VDEwLjMgMTguM3ptMy02LjE1TDcuODUgMTFINXYyaDIuODVMMTAgMTUuMTV6TTcuNSAxMiIvPjwvc3ZnPg==",n="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSIjNjA2MDYwIiBkPSJNMTkgMTEuOTc1cTAtMi4wNzUtMS4xLTMuNzg3dC0yLjk1LTIuNTYzcS0uMzc1LS4xNzUtLjU1LS41Mzd0LS4wNS0uNzM4cS4xNS0uNC41MzgtLjU3NXQuNzg3IDBRMTguMSA0Ljg1IDE5LjU1IDcuMDYzVDIxIDExLjk3NHQtMS40NSA0LjkxM3QtMy44NzUgMy4yODdxLS40LjE3NS0uNzg4IDB0LS41MzctLjU3NXEtLjEyNS0uMzc1LjA1LS43Mzd0LjU1LS41MzhxMS44NS0uODUgMi45NS0yLjU2MnQxLjEtMy43ODhNNyAxNUg0cS0uNDI1IDAtLjcxMi0uMjg4VDMgMTR2LTRxMC0uNDI1LjI4OC0uNzEyVDQgOWgzbDMuMy0zLjNxLjQ3NS0uNDc1IDEuMDg4LS4yMTN0LjYxMi45Mzh2MTEuMTVxMCAuNjc1LS42MTIuOTM4VDEwLjMgMTguM3ptOS41LTNxMCAxLjA1LS40NzUgMS45ODh0LTEuMjUgMS41MzdxLS4yNS4xNS0uNTEzLjAxM1QxNCAxNS4xVjguODVxMC0uMy4yNjMtLjQzN3QuNTEyLjAxMnEuNzc1LjYyNSAxLjI1IDEuNTc1dC40NzUgMk0xMCA4Ljg1TDcuODUgMTFINXYyaDIuODVMMTAgMTUuMTV6TTcuNSAxMiIvPjwvc3ZnPg==";async function o(e){const t=await fetch(e),i=await t.arrayBuffer(),n=function(e){const t=(new TextDecoder).decode(e);let i=t.match(/MicroVideoOffset=["']?(\d+)["']?/);i||(i=t.match(/MicroVideoOffset>(\d+)</));if(i){const t=parseInt(i[1],10);return e.byteLength-t}const n=new Uint8Array(e),o=[102,116,121,112];for(let e=0;e<n.length-4;e++)if(n[e]===o[0]&&n[e+1]===o[1]&&n[e+2]===o[2]&&n[e+3]===o[3])return e-4;return-1}(i);if(n>0)return{video:new Blob([i.slice(n)],{type:"video/mp4"})};throw new Error("No video found in Android Live Photo")}async function s(e){const t=await fetch(e),i=await t.arrayBuffer(),n=await async function(e){const t=new DataView(e),i={},n=101010256;let o=-1;for(let i=e.byteLength-22;i>=0;i--)if(t.getUint32(i,!0)===n){o=i;break}if(-1===o)throw new Error("Invalid ZIP file");const s=t.getUint32(o+16,!0),c=t.getUint16(o+10,!0);let r=s;for(let n=0;n<c&&!(r>=e.byteLength);n++){if(33639248!==t.getUint32(r,!0))break;const n=t.getUint16(r+10,!0),o=t.getUint32(r+20,!0),s=t.getUint16(r+28,!0),c=t.getUint16(r+30,!0),a=t.getUint16(r+32,!0),d=t.getUint32(r+42,!0),l=new Uint8Array(e,r+46,s),u=(new TextDecoder).decode(l);r+=46+s+c+a;const h=d+30+t.getUint16(d+26,!0)+t.getUint16(d+28,!0),M=e.slice(h,h+o);let g=null;if(0===n)g=new Blob([M]);else if(8===n&&"undefined"!=typeof DecompressionStream)try{const e=new DecompressionStream("deflate-raw"),t=new Response(new Blob([M]).stream().pipeThrough(e));g=await t.blob()}catch(e){console.warn("Decompression failed for:",u,e)}if(g)if(u.toLowerCase().endsWith(".mov"))i.video=new Blob([g],{type:"video/quicktime"});else if(/\.(heic|jpg|jpeg|png)$/i.test(u)&&(!i.image||u.toLowerCase().endsWith(".heic"))){const e=u.toLowerCase().endsWith(".heic")?"image/heic":u.toLowerCase().endsWith(".png")?"image/png":"image/jpeg";i.image=new Blob([g],{type:e})}}return i}(i);return n}class c{constructor(e,t={}){if(this.container="string"==typeof e?document.querySelector(e):e,!this.container)return;const i=t.width||this.container.dataset.width,n=t.height||this.container.dataset.height;this.autoSize=!i||!n,this.options={videoSrc:t.videoSrc||this.container.dataset.video||"",imageSrc:t.imageSrc||this.container.dataset.image,type:t.type||this.container.dataset.type||"android",width:i||0,height:n||0,alt:t.alt||"",iconText:t.iconText||"实况",mute:void 0===t.mute||t.mute},this.options.imageSrc?(this.isMuted=this.options.mute,this.observer=new IntersectionObserver(e=>{e.forEach(e=>{e.isIntersecting&&(this.init(),this.observer.disconnect())})}),this.observer.observe(this.container)):console.warn("[LivePhoto] 缺少 imageSrc,无法初始化该实例")}init(){if(this.render(),this.bindEvents(),!this.options.videoSrc&&this.options.imageSrc){const e=this.options.type.toLowerCase(),t=t=>{if(t.video){const i=URL.createObjectURL(t.video);this.elements.video.src=i,this.options.videoSrc=i,"android"!==e&&(this.elements.video.loop=!0)}if(t.image){const e=URL.createObjectURL(t.image);this.elements.image.src=e}};"android"===e?o(this.options.imageSrc).then(t).catch(e=>console.warn("[LivePhoto] Auto parse failed:",e)):"apple"===e||this.options.imageSrc.toLowerCase().endsWith(".livp")?s(this.options.imageSrc).then(t).catch(e=>console.warn("[LivePhoto] Apple LivePhoto parse failed:",e)):(console.warn("[LivePhoto] 无法识别的 LivePhoto 类型,默认尝试 Android 解析"),o(this.options.imageSrc).then(t).catch(e=>console.warn("[LivePhoto] Auto parse failed:",e)))}}render(){const{width:e,height:t,videoSrc:o,imageSrc:s,alt:c,iconText:r}=this.options,a=(e/t).toFixed(4);if(this.container.innerHTML=`\n <div class="live-photo" style="width: ${e}px; aspect-ratio: ${a}">\n <div class="container">\n <video src="${o}" ${this.isMuted?"muted":""} playsinline preload="metadata"></video>\n <img src="${s}" alt="${c}" loading="lazy" />\n </div>\n <div class="controls">\n <div class="icon">\n <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGvklEQVR4nO2ce4gVVRzHP7vr3dp1JfOFWWGvzXLLtXzTm95qURQVltrDIJI0LaKEkiAjDLW0gsRqe2FrEhT0R2gvFSmxNR/rHybbw0pLrXyUq1YbB74Dh8X2njMzd+7cdT4wMLN7zsyZ35zH73UuZGRkZGRkZGRkZBSH3kBPnZcD7wHzdF0JNAPv6LoMeBy4gaOcSuv8e+AnnXcBtgFrrHJbgLd13Qf4F1il625AI3ATRxGvAr8BfXX9FPC89f9qoKqD+pcC/XVeL4G+ouuuEuaxdCKqgHusYWqG4Hqge0z3P9sS+GNAG3AvnYg79FJPJ/CsU4HZGuqGW3WUHKcAV1vz1Axr2CXJPmAnJcjH6nWnF7kdFwIjdd4DGEqJcCXwBFBBeliqj1pHSnkBWCZVJI2MBl7Ks8IXleXS50pBhbhOi1qaRgim5+UoDZZLfzSLXVF5GPgTGExpcTJwESlgEvAtcBaliRkxs4Cr6ATUA9OBJbJUjLl3SIc5/1r/mwYMiumZA7Qyf0jCNAALY7hPNwlts17E52iWMGsituEyoB8JYlxKP+gFoiw45uV3WwL5GVgEjAfOl+2c09ELGAJMkONgu1VvFzA1BvXpzCStpaoI+tQAoMkSwKfAGE+VwghrLPC5dZ+vgNqQbSqX2fcdBWaQZRqF1b/26oW3xDR5Xwts1T336mOEYYZ6ckHZLrXFDOMwXpnDetEG+e7iwsyDb+re5hnjSCkTpbqE6XmH9YLGH1goZuoZh2S6+dJTHm7Tq1PDAM0vhRZeeyHuCTEnDpOF8nLcjeqvIWJ0NTwn+yZr2CbFW3rm2hD27jkKK8TKBDXoIc9606wFI845z2VODBaWB0gB5Vp9c55K8m69ROCdTpLRevZOz49nFsjVwAcUmemWnudDneLCm4D9Ojbpb77O0BVqw4OeAvxCXvVYOE92qPEy+7BZjXfVy0wMeAHwdwfmm/nf/HZx5Xyrv6m3kSJyvRpxt0edess8czGxKuXNNnUOAM8BwzX0zDFCseNWlVnmKETz7B0hXflVIfXdI3J8yOG7yLH8ApU3Nva5eT7MNpU1PdGF11Tex8o4A/jLSjFJnCVqtHEM5KNOQ/NAHuHZQmxVnYGOyn+blV/jqlCvjcu0MzrVJ57deb0abbwq+Zinsj5fe77qzHUoO1Rl11EkVmoV9FFId6nRQTpHRzSrrLECXBnhsTj0ttQZH6rjUqjLQ2jzB9Vol4k+8M7UeOqYgfclH8eorBn2Pnyjoygc7AQCXCk9MjKN0sxNTyzkEB7ucf+RCQzh2HhftmxFiEVkiMciYucIuqo9cxzKDiv2IkKIObBRjTZOCFc1ptXR2zNYU4SrGnOn2rIYv7jx78CzFIlpanSQOeqqlmzLI0QjvB9V1lgrLjSo/BTcOUGjziQOROZiufGNQuoTO2lTCMDFlMtZplyrBDpSC4s5RmnYBovTMkfPkCnzi+q49NaCMEQ27W2e9ZrVcBM9c6FSguvImXBYPS/nacdv8Gx7dcL+yw6HsQk9+lAnC2OjQgH7dD4nRC9aFcIORsPXHLFykqc5V2OpM8UI0gSurF9D9KY3lEsYG2PVmEc8601Vva0xpGDgqWi36NmTSQEm1/kz4ArPel2UMdCmoFRSLNYz14RQwS4HTiRF1Frmmgk5Fpon9aw/QiS5B45gk09dEEwm040h6o2xAuszExCeCaxfE6K+sZufUXZ/QTDeiX9CunnG6cXa5GOsiXnOC4btoRAqV2KYL3NzxFDjHmthCZN+caTVtsUatmF6Hko6N8p66qmVuzxQjldICD75fTkpyYGeFywYUTb2tMhgSITVsjTKQtavUMbATksAOxQAmig3fC9ZJ5U6HybHQINlngV63uQYtiz0cHS/xcJSBZ7LIt6nq4LeG0Ok+G6QnhnV5LrF0e2WeuokkEb57nbLeXBQFs06RdamxOgY6KuP8SVFYoycpy7hyLQyqZh7RqZKrSlG8lAUTpNaFVvmQRSOo/R4V0PXhEdTw0KtpGY1SzsmYerRtO0snS0fWlp75Gjl/AU/dpFq6vUDEK5paEkwV8P2AkqAxWpswYxyRy6xnB+VKfgJAq+k9NuttJD7IuwiisIWaQmp3aXu6gIzvfF1Ck8/ueIHWhHFKM6PVJCTrVpr7VhaF+PGvjrZyki3a9MPXnRaZsk8C/b83q+fgwqcAdXy7/0fo6xUuD5y1AaRv3Ltv4t9n0eaKGvnAFipTPxA/WmSW6nC+n+TVXe/9M1AYCZOfBdHMd0VMg14sd2upo8kxIDxjjk3GRkZGRkZGRkZGRSK/wDiCstGS04B5wAAAABJRU5ErkJggg==" alt="live-icon" />\n <span>${r}</span>\n </div>\n <div class="volume-control">\n <img src="${this.isMuted?i:n}" class="volume-icon" />\n </div>\n </div>\n <div class="warning"></div>\n </div>\n `,this.elements={wrapper:this.container.querySelector(".live-photo"),video:this.container.querySelector("video"),image:this.container.querySelector("img"),icon:this.container.querySelector(".icon"),volumeControl:this.container.querySelector(".volume-control"),volumeIcon:this.container.querySelector(".volume-icon"),warning:this.container.querySelector(".warning")},this.autoSize){const e=()=>{const{naturalWidth:e,naturalHeight:t}=this.elements.image;if(e&&t){const i=(e/t).toFixed(4);this.elements.wrapper.style.width=`${e}px`,this.elements.wrapper.style.aspectRatio=i}};this.elements.image.complete?e():this.elements.image.onload=e}}bindEvents(){const e=e=>this.handleStart(e),t=()=>this.handleStop();this.elements.icon.addEventListener("mouseenter",e),this.elements.wrapper.addEventListener("mouseleave",t),this.elements.icon.addEventListener("touchstart",e,{passive:!1}),this.elements.wrapper.addEventListener("touchend",t),this.elements.video.addEventListener("ended",()=>{this.elements.wrapper.classList.remove("zoom")}),this.elements.volumeControl.addEventListener("click",e=>{e.stopPropagation(),this.isMuted=!this.isMuted,this.elements.video.muted=this.isMuted,this.elements.volumeIcon.src=this.isMuted?i:n})}async handleStart(e){e.cancelable&&e.preventDefault();try{this.elements.video.currentTime=0,this.elements.video.muted=this.isMuted,await this.elements.video.play(),this.elements.wrapper.classList.add("zoom"),this.elements.warning.classList.remove("show")}catch(e){this.showWarning("播放失败: 尝试点击一下以允许播放")}}handleStop(){this.elements.wrapper.classList.remove("zoom"),this.elements.video.pause()}showWarning(e){this.elements.warning.textContent=e,this.elements.warning.classList.add("show")}}function r(e){console.log("[LivePhoto] 初始化类名:",e);const t=document.querySelectorAll(e);t.forEach(e=>new c(e)),console.log(`[LivePhoto] 已初始化 ${t.length} 个实例`)}return t})());
|
package/dist/main.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.live-photo{border-radius:var(--border-radius,8px);container-type:inline-size;height:auto!important;margin:1em auto;max-width:min(400px,100%);overflow:hidden;position:relative}.live-photo .container{height:100%;position:absolute;width:100%}.live-photo .container img,.live-photo .container video{height:100%;object-fit:cover;position:absolute;width:100%}.live-photo .container img{transition:opacity 1s ease,transform 1s ease}.live-photo .container video{transition:transform 1s ease}.live-photo.zoom .container img,.live-photo.zoom .container video{transform:scale(1.1)}.live-photo.zoom .container img{opacity:0}.live-photo.zoom .icon img{animation:spin 5s linear infinite}.live-photo .controls{align-items:center;column-gap:6px;display:inline-flex;left:10px;position:relative;top:10px}.live-photo .icon{align-items:center;background-color:rgba(240,255,255,.67);border-radius:var(--border-radius,8px);cursor:pointer;display:inline-flex;height:20px;padding:2px;user-select:none}.live-photo .icon img{height:22px;width:22px}.live-photo .icon span{color:#606060;font-size:80%;padding:3px}@container (max-width: 200px){.live-photo .icon span{display:none}}.live-photo .warning{background-color:rgba(240,255,255,.67);border-radius:var(--border-radius,8px);color:#9a6700;display:none;left:0;margin:10px;opacity:0;padding:4px 6px;position:absolute;top:40px;transition:opacity .5s linear}.live-photo .warning.show{display:inline-block!important;opacity:1!important}.live-photo .volume-control{align-items:center;background-color:rgba(240,255,255,.67);border-radius:var(--border-radius,8px);cursor:pointer;display:inline-flex;height:20px;justify-content:center;padding:2px;transition:background-color .2s ease;user-select:none;width:20px}.live-photo .volume-control:hover{background-color:rgba(240,255,255,.9)}.live-photo .volume-control .volume-icon{height:18px;width:18px}@keyframes spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thun888/live-photo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "dist/bundle.js",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist"
|
|
7
|
+
],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "webpack",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"css-loader": "^7.1.3",
|
|
15
|
+
"css-minimizer-webpack-plugin": "^7.0.4",
|
|
16
|
+
"mini-css-extract-plugin": "^2.10.0",
|
|
17
|
+
"style-loader": "^4.0.0",
|
|
18
|
+
"terser-webpack-plugin": "^5.3.16",
|
|
19
|
+
"webpack": "^5.105.2",
|
|
20
|
+
"webpack-bundle-analyzer": "^5.2.0",
|
|
21
|
+
"webpack-cli": "^6.0.1"
|
|
22
|
+
}
|
|
23
|
+
}
|