const getPosition = element => { let x = 0; let y = 0; while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { x += element.offsetLeft - element.scrollLeft; y += element.offsetTop - element.scrollTop; element = element.offsetParent; } return { x: x, y: y, }; }; const secondsToTime = sec => { sec = Math.abs(sec); const hours = Math.floor(sec / 3600); const minutes = Math.floor((sec - hours * 3600) / 60); const seconds = sec - hours * 3600 - minutes * 60; let result = fixed(seconds) + "秒"; if (minutes > 0) { result = minutes + "分" + result; } if (hours > 0) { result = hours + "时" + result; } return result; }; const secondsToHms = sec => { sec = Math.abs(sec); const hours = Math.floor(sec / 3600); const minutes = Math.floor((sec - hours * 3600) / 60); const seconds = sec - hours * 3600 - minutes * 60; let result = (seconds < 10 ? "0" : "") + fixed(seconds); result = (minutes < 10 ? "0" : "") + minutes + ":" + result; result = (hours < 10 ? "0" : "") + hours + ":" + result; return result; }; class Swiper { constructor(element) { this.action = new SwipeAction(element); this.onTouchStart = null; this.onTouchEnd = null; this.direction = null; element.addEventListener("touchstart", e => { this.xDown = e.touches[0].clientX; this.yDown = e.touches[0].clientY; if (this.onTouchStart) { this.onTouchStart(e); } }); element.addEventListener("touchmove", e => { if (!this.xDown || !this.yDown) { return; } const xUp = e.touches[0].clientX; const yUp = e.touches[0].clientY; const elementPosition = getPosition(element); const position = { x: (e.touches[0].pageX - elementPosition.x) / element.clientWidth, y: (e.touches[0].pageY - elementPosition.y) / element.clientHeight, width: element.clientWidth, height: element.clientHeight, }; const xDiff = this.xDown - xUp; const yDiff = this.yDown - yUp; if (!this.direction) { let direction = ""; if (Math.abs(xDiff) > Math.abs(yDiff)) { direction = "horizontal"; } else { direction = "vertical"; } this.direction = direction; e.preventDefault(); } else { if (this.direction === "vertical") { this.action.startAction(this.direction, yDiff, position); } else if (this.direction === "horizontal") { this.action.startAction(this.direction, -xDiff, position); } e.preventDefault(); } }); element.addEventListener("touchend", e => { this.xDown = null; this.yDown = null; this.direction = null; if (this.onTouchEnd) { this.onTouchEnd(e); } }); } } class SwipeAction { constructor(element) { this.lowSpeedForward = null; this.lowSpeedBackward = null; this.mediumSpeedForward = null; this.mediumSpeedBackward = null; this.highSpeedForward = null; this.highSpeedBackward = null; this.lowVolumeUp = null; this.lowVolumeDown = null; this.mediumVolumeUp = null; this.mediumVolumeDown = null; this.highVolumeUp = null; this.highVolumeDown = null; this.speedCancel = null; this.volumeCancel = null; this.minSwipeDistance = 20; this.onActionStart = null; this.onActionEnd = null; this.element = element; this.touchStart = false; this.startPosition = null; this.lastAction = null; element.addEventListener("touchstart", e => { this.touchStart = true; }); element.addEventListener("touchend", e => { this.startPosition = null; this.onActionEnd && this.onActionEnd(this.lastAction); this.lastAction = null; }); } startAction(direction, distance, position) { if (this.touchStart) { this.onActionStart && this.onActionStart(direction); this.startPosition = position; this.touchStart = false; } if (direction === "vertical") { if (Math.abs(distance) < this.minSwipeDistance) { this.volumeCancel && this.volumeCancel(); this.lastAction = null; } else { let volumeFactor = 0; let upHandler = undefined; let downHandler = undefined; if (this.startPosition.x < 1 / 3) { volumeFactor = 0.4; upHandler = this.lowVolumeUp; downHandler = this.lowVolumeDown; } else if (this.startPosition.x >= 1 / 3 && this.startPosition.x <= 2 / 3) { volumeFactor = 1; upHandler = this.mediumVolumeUp; downHandler = this.mediumVolumeDown; } else { volumeFactor = 2; upHandler = this.highVolumeUp; downHandler = this.highVolumeDown; } if (distance > 0) { const volumeChange = Math.round( volumeFactor * 100 * (distance - this.minSwipeDistance) / (1.5 * position.height) ); upHandler && upHandler(volumeChange); this.lastAction = { type: "volume", volume: volumeChange, }; } else { const volumeChange = Math.round( volumeFactor * 100 * (distance + this.minSwipeDistance) / (1.5 * position.height) ); downHandler && downHandler(volumeChange); this.lastAction = { type: "volume", volume: volumeChange, }; } } } else if (direction === "horizontal") { if (position.y < 1 / 3 && (position.x < 0.1 || position.x > 0.9) || Math.abs(distance) < this.minSwipeDistance) { this.speedCancel && this.speedCancel(); this.lastAction = null; } else { let speedFactor = 0; let forwardHandler = undefined; let backwardHandler = undefined; if (this.startPosition.y < 1 / 3) { speedFactor = 0.05; forwardHandler = this.lowSpeedForward; backwardHandler = this.lowSpeedBackward; } else if (this.startPosition.y >= 1 / 3 && this.startPosition.y <= 2 / 3) { speedFactor = 0.2; forwardHandler = this.mediumSpeedForward; backwardHandler = this.mediumSpeedBackward; } else { speedFactor = 1; forwardHandler = this.highSpeedForward; backwardHandler = this.highSpeedBackward; } if (distance > 0) { const seconds = (distance - this.minSwipeDistance) * speedFactor; forwardHandler && forwardHandler(seconds); this.lastAction = { type: "playback", seconds: seconds, }; } else { const seconds = (distance + this.minSwipeDistance) * speedFactor; backwardHandler && backwardHandler(seconds); this.lastAction = { type: "playback", seconds: seconds, }; } } } } } class VideoShot { constructor() { this.aid = unsafeWindow.aid; this.cid = unsafeWindow.cid; this.cidData = null; this.supportWebp = VideoShot.supportWebp; } getVideoshot(currentTime, done) { if (!(this.aid && this.cid)) { return; } if (!this.cidData) { Ajax.getText(`https://api.bilibili.com/x/player/videoshot?aid=${this.aid}&cid=${this.cid}&index=1`).then(response => { this.cidData = JSON.parse(response).data; this.getVideoshot(currentTime, done); }); } else { const data = this.cidData; const indexData = data.index; let shotIndex = 0; for (let index = 0; index < indexData.length - 2; index++) { if (currentTime >= indexData[index] && currentTime < indexData[index + 1]) { shotIndex = index; break; } } let imageData = data.image; if (this.supportWebp) { imageData = imageData.map(url => url.replace(".jpg", ".jpg@.webp")); } const xLength = parseInt(data.pv_x_len) || 10; const yLength = parseInt(data.pv_y_len) || 10; const xSize = parseInt(data.pv_x_size) || 160; const ySize = parseInt(data.pv_y_size) || 90; const x = -(shotIndex % 100 % xLength) * xSize; const y = -Math.floor(shotIndex % 100 / yLength) * ySize; done({ width: xSize, height: ySize, backgroundImage: `url(${imageData[Math.floor(shotIndex / 100)]})`, backgroundPosition: `${x}px ${y}px`, }); } } static get supportWebp() { try { const canvas = document.createElement("canvas"); if (canvas.getContext && canvas.getContext("2d")) try { return canvas.toDataURL("image/webp").indexOf("data:image/webp") === 0; } catch (ex) { return false; } else return false; } catch (ex) { return false; } } } function unbindIconsClick(icons) { icons.unbind("click"); } function setupTouchPlayer(player) { if ($(".touch-video-box").length !== 0) { return; } $(".bilibili-player-video-subtitle").before(/*html*/`