/** * 创建广告 * config 参数说明 * @param {string[]} ad_id 广告id * @param {string} ad_type 广告类型 1:视频 2:图片 * @param {string} ad_pos 广告位置 * @param {string[]} ad_size 广告尺寸 * @param {string} ad_text 广告文案 * @param {string[]} ad_url 广告链接 * @param {string[]} ad_cover 广告图片 */ document.addEventListener('DOMContentLoaded', function () { const agreement = location.origin === 'http://' ? 'http:' : location.origin === 'https://' ? 'https:' : 'http://' const base = agreement + 'ads-qidian.sxtvs.com/' /** * 广告初始化 * @param config 广告配置 * @returns */ function ad_init(config = {}) { // 启动上报 const slots = config.slots || [] const D = new Date() const dateTime = D.getTime() for (let i = 0; i < slots.length; i++) { const v = slots[i] // 获取对应广告位置 const ad_pos = document.querySelector('#sxtv-ad-' + v.slotId) if (!ad_pos) { console.error('广告位置不存在:#sxtv-ad-' + v.slotId) continue } ad_pos.style.width = (v.width || 0) + 'px' ad_pos.style.height = (v.height || 0) + 'px' ad_pos.style.overflow = 'hidden' ad_pos.style.position = 'relative' if (!v.creativesList || !v.creativesList.length) { if (v.baseMaterial) ad_pos.appendChild(generateDefaultAd(v)) continue } const gg = document.createElement('div') gg.innerHTML = '' gg.style.position = 'absolute' gg.style.top = 0 gg.style.right = 3 gg.style.zIndex = 999999 ad_pos.appendChild(gg) // 判定当前时间是否在creativesList的时间内 let show = false for (let o = 0; o < v.creativesList.length; o++) { const item = v.creativesList[o] const start = new Date(item.startDate + ' 00:00:00').getTime() const end = new Date(item.endDate + ' 23:59:59').getTime() // 判断变量是否数组 if (dateTime < start || dateTime > end || !Array.isArray(item.stuffsList)) continue // 获取广告类型 1 轮播 2 交替 3 单项 const showType = item.showType let e = showType === 1 ? generateCarouselAd(item, D, v.slotId, v.width || 0, v.height || 0) : generateAlternateAd(item, D, v.slotId, v.width || 0, v.height || 0) if (e == -1 && !v.baseMaterial) continue // 使用打底素材 if (e == -1) e = generateDefaultAd(v) show = true ad_pos.appendChild(e) } ad_pos.style.display = show ? 'block' : 'none' } } // 投放打底素材 function generateDefaultAd(v) { const fileType = v.baseMaterial.split('.').pop() if (fileType === 'jpg' || fileType === 'png' || fileType === 'gif') { const son_ele = document.createElement('img') son_ele.src = v.baseMaterial son_ele.style.width = '100%' son_ele.style.height = '100%' return son_ele } const son_ele = document.createElement('video') son_ele.setAttribute('loop', 'loop') son_ele.setAttribute('autoplay', 'autoplay') son_ele.muted = true son_ele.src = v.baseMaterial son_ele.style.width = '100%' son_ele.style.height = '100%' son_ele.oncanplay = () => son_ele.play() // 对body添加一次性点击事件 const play = () => { son_ele.play() // 移除点击 document.body.removeEventListener('click', play) document.body.removeEventListener('mousemove', play) } // 鼠标移动时间 document.body.addEventListener('mousemove', play) document.body.addEventListener('click', play) return son_ele } // 生成轮播广告 const generateCarouselAd = function (generateCarousel = {}, D, slotId, width, height) { const week = D.getDay() === 0 ? 6 : D.getDay() - 1 const timeInterval = (generateCarousel.timeInterval || '') .slice(week * 24, week * 24 + 24) .split('') const H = D.getHours() if (generateCarousel.intervalType === 2 && timeInterval[H] == 0) return -1 if (!generateCarousel.stuffsList || !generateCarousel.stuffsList.length) return -1 const T = (generateCarousel.showIntervalTime || 5) * 1000 return createCarousel(generateCarousel.stuffsList, T, slotId, width, height) } // 生成交替广告 const generateAlternateAd = function (generateAlternate = {}, D, slotId, width, height) { const week = D.getDay() === 0 ? 6 : D.getDay() - 1 const timeInterval = (generateAlternate.timeInterval || '') .slice(week * 24, week * 24 + 24) .split('') const H = D.getHours() if (generateAlternate.intervalType === 2 && timeInterval[H] == 0) return -1 const stuff = generateAlternate.stuffsList[ Math.floor((H * 60 + D.getMinutes()) / showIntervalTime) % generateAlternate.stuffsList.length ] if (!stuff) return -1 const fileType = stuff.addr.split('.').pop() // fileType是否是图片类型 if (fileType === 'jpg' || fileType === 'png' || fileType === 'gif') { const son_ele = document.createElement('img') son_ele.src = stuff.addr son_ele.style.width = width + 'px' son_ele.style.height = height + 'px' son_ele.onload = () => { const uuid = localStorage.getItem('ad_id') fetch(`${base}ad/show?uuid=${uuid}&stuffId=${stuff.stuffId}&slotId=${slotId}`).then((res) => res.text(), ) } son_ele.addEventListener('click', () => { if (!stuff.landingPage) return const uuid = localStorage.getItem('ad_id') // 点击广告 fetch(`${base}ad/click?uuid=${uuid}&stuffId=${stuff.stuffId}&slotId=${slotId}`) .then((res) => res.text()) .then(() => { window.open(stuff.landingPage) }) }) return son_ele } const son_ele = document.createElement('video') son_ele.setAttribute('loop', 'loop') son_ele.setAttribute('autoplay', 'autoplay') son_ele.muted = true son_ele.src = stuff.addr son_ele.style.width = '100%' son_ele.style.height = '100%' // 视频加载允许播放的回调 son_ele.oncanplay = () => { son_ele.play() const uuid = localStorage.getItem('ad_id') fetch(`${base}ad/show?uuid=${uuid}&stuffId=${stuff.stuffId}&slotId=${slotId}`) } son_ele.addEventListener('click', () => { if (!stuff.landingPage) return const uuid = localStorage.getItem('ad_id') window.open(stuff.landingPage) // 点击广告 fetch(`${base}ad/click?uuid=${uuid}&stuffId=${stuff.stuffId}&slotId=${slotId}`) }) // 对body添加一次性点击事件 const play = () => { son_ele.play() // 移除点击 document.body.removeEventListener('click', play) document.body.removeEventListener('mousemove', play) } // 鼠标移动时间 document.body.addEventListener('mousemove', play) document.body.addEventListener('click', play) return son_ele } function generateBrowserFingerprint() { return new Promise((resolve, reject) => { // 在这里执行获取指纹的操作,例如使用Canvas、WebGL等方法 // 然后将生成的指纹字符串作为参数传递给resolve函数 // 获取浏览器信息 const browserInfo = `${navigator.userAgent} ${window.screen.width}x${window.screen.height}` // 获取时区偏移量 const timezoneOffset = Intl.DateTimeFormat().resolvedOptions().timeZone // 在这里处理获取到的指纹信息 const canvasFingerprint = getCanvasFingerprint() const webglFingerprint = getWebglFingerprint() // 将所有信息组合成一个字符串 const fingerprintStr = `${browserInfo}|${timezoneOffset}|${canvasFingerprint}|${webglFingerprint}` // 使用createHash生成哈希值 createHash(fingerprintStr) .then((hash) => { resolve(hash) }) .catch((error) => { reject(error) }) }) } // Canvas指纹获取函数 function getCanvasFingerprint() { const canvas = document.createElement('canvas') const ctx = canvas.getContext('2d') if (!ctx) return '' // 绘制一些内容 ctx.fillStyle = '#f60' ctx.fillRect(0, 0, 16, 16) ctx.fillStyle = '#069' ctx.font = '11pt Arial' ctx.fillText('Cwm fjord!!', 4, 10) ctx.fillStyle = 'rgba(102, 204, 0, 0.7)' ctx.fillText('Cwm fjord!!', 5, 11) ctx.scale(2, 2) ctx.fillStyle = '#fff' ctx.font = '24pt Arial' ctx.fillText('Cwm fjord!!', 10, 25) ctx.fillStyle = 'rgba(102, 204, 0, 0.7)' ctx.fillText('Cwm fjord!!', 10, 25) const data = canvas.toDataURL() return data.replace(/data:image\/png;base64,/, '') } // WebGL指纹获取函数 function getWebglFingerprint() { const canvas = document.createElement('canvas') const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') if (!gl) return '' const extensions = gl.getSupportedExtensions() if (!extensions) return '' const extStr = extensions.join(',') const rendererInfo = gl.getParameter(gl.RENDERER) + '/' + gl.getParameter(gl.VENDOR) return rendererInfo + extStr } function createHash(str) { // 使用 SubtleCrypto API 计算 SHA-256 摘要 return new Promise((resolve, reject) => { var script = document.createElement('script') script.type = 'text/javascript' script.src = agreement + 'assets.qidian.sxtvs.com/ads/jsSDK/crypto-js.min.js' // 脚本加载完成后的回调函数 script.onload = function () { resolve(CryptoJS.SHA256(str).toString()) } // 脚本加载失败的处理 script.onerror = function () { console.error('无法生成广告指纹') reject('无法生成广告指纹') } // 将脚本元素追加到文档的部分或者部分 document.head.appendChild(script) }) } // 轮播 function createCarousel(images, interval, slotId, width, height) { // 创建轮播图容器 const carouselContainer = document.createElement('div') carouselContainer.style = ` position: relative; width: 100%; height: 100%; margin: auto; overflow: hidden; ` // 创建图片容器 const imagesContainer = document.createElement('div') imagesContainer.style = ` width: ${images.length * width}px; height: ${height}px; display: flex; transition: transform 0.5s ease; ` // 创建指示器容器 const indicatorsContainer = document.createElement('div') indicatorsContainer.style = ` position: absolute; bottom: 10px; left: 50%; margin-right: 5px; transform: translateX(-50%); ` // 添加图片到容器 images.forEach((src, index) => { const img = document.createElement('img') img.src = src.addr img.alt = `Image ${index + 1}` img.style = ` flex: 1; width: ${width}px; height: 100%; ` img.addEventListener('click', () => { if (!src.landingPage) return const uuid = localStorage.getItem('ad_id') // 点击广告 fetch(`${base}ad/click?uuid=${uuid}&stuffId=${src.stuffId}&slotId=${slotId}`) .then((res) => res.text()) .then(() => { window.open(src.landingPage) }) }) // 图片加载完成 img.onload = () => { const uuid = localStorage.getItem('ad_id') fetch(`${base}ad/show?uuid=${uuid}&stuffId=${src.stuffId}&slotId=${slotId}`).then((res) => res.text(), ) } imagesContainer.appendChild(img) // 添加指示器 const indicator = document.createElement('button') indicator.style = ` border: none; background-color: #fff; cursor: pointer; padding: 5px; border-radius: 50%; width: 10px; height: 10px; margin-right: 5px; display: inline-block; ` if (index !== 0) indicator.style.backgroundColor = '#ccc' indicator.dataset.target = index indicatorsContainer.appendChild(indicator) }) // 将图片容器和指示器容器添加到轮播图容器 carouselContainer.appendChild(imagesContainer) carouselContainer.appendChild(indicatorsContainer) // 设置轮播图的切换逻辑 let currentImageIndex = 0 const maxImages = images.length function showImage(index) { // 更新图片位置 imagesContainer.style.transform = `translateX(-${index * width}px)` // 更新指示器 indicatorsContainer.querySelectorAll('button').forEach((btn, i) => { btn.style.backgroundColor = i === index ? '#000' : '#ccc' }) currentImageIndex = index } function nextImage() { currentImageIndex = (currentImageIndex + 1) % maxImages showImage(currentImageIndex) } // 为指示器添加点击事件 indicatorsContainer.addEventListener('click', function (e) { if (e.target.tagName === 'BUTTON') { const targetIndex = parseInt(e.target.dataset.target) showImage(targetIndex) } }) // 自动播放轮播图 let intervalId = setInterval(nextImage, interval) // 可选:鼠标悬停时停止自动播放 carouselContainer.addEventListener('mouseenter', () => { clearInterval(intervalId) }) carouselContainer.addEventListener('mouseleave', () => { intervalId = setInterval(nextImage, interval) }) return carouselContainer } // 轮播End const script = document.querySelector('#sxtv-ad-id') const CFG = agreement + 'assets.qidian.sxtvs.com/ads/catalog/' + script.getAttribute('ad_id') + '.json' try { fetch(CFG + '?' + Date.now()) .then((res) => res.json()) .then((res) => { const data = res // 广告sdk if (localStorage.getItem('ad_id')) { ad_init(data) return } // 生成并输出浏览器指纹 generateBrowserFingerprint().then((ad_id) => { localStorage.setItem('ad_id', ad_id + '') ad_init(data) }) }) } catch (error) { console.error(error) } })