dalin94tiancai
发表于 2024-10-6 12:31
ASFASFGADFBGFFGJGHK
wmj0518
发表于 2024-10-6 12:31
感谢分享:lol
花樣年華
发表于 2024-10-6 12:31
感谢分享
ilgtaforever
发表于 2024-10-6 12:32
6666666666666666666
刺客老王
发表于 2024-10-6 12:32
6666666666666666666666666666666666666
roxas128
发表于 2024-10-6 12:32
感谢分享。。。。
chenyuchloe
发表于 2024-10-6 12:32
沙发?不错
丨燕尾鱼丨
发表于 2024-10-6 12:32
感谢分享
as123045600
发表于 2024-10-6 12:32
666666666666666666666666
minipo
发表于 2024-10-6 12:32
6666666666666666
hawktwo
发表于 2024-10-6 12:32
:victory::lol:victory:
liyuecool
发表于 2024-10-6 12:32
可以可以 今年大作之一啊,值得一玩
一事V无成
发表于 2024-10-6 12:32
666666666666666
srxpes
发表于 2024-10-6 12:32
666666666666666666
yyt46456
发表于 2024-10-6 12:32
666666666666666666666666666666
jack000036
发表于 2024-10-6 12:32
感谢分享
kdstvr
发表于 2024-10-6 12:32
是时候了
hkguty
发表于 2024-10-6 12:32
ddddddddddddd
♂搓澡巾XL
发表于 2024-10-6 12:32
good~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
普洱大仙儿
发表于 2024-10-6 12:32
Silent.Hill.2.Remake-RUNE
愉悦王金闪闪
发表于 2024-10-6 12:32
谢谢分享!!!
zyz007zjjx
发表于 2024-10-6 12:32
同附件下载不了
茶菌丶
发表于 2024-10-6 12:32
:(:(:(:(:(
御剑随风
发表于 2024-10-6 12:32
终于来了
ww200ww
发表于 2024-10-6 12:32
{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}{:3_94:}
qq103517775
发表于 2024-10-6 12:32
; option.value tin.textontentvodeoVlume = null; visendMessageTo(this.m3u8PostWindows, MessageType.FetchRealUrlReq, { url: url, origin: origin }); } }) } } async testM3u8OrVideoUrl(testUrl) { const onsecuritypolicyviolation = (e) => { if (e.blockedURI == testUrl) { // m3u8 can always be fetched, because hls.js this.m3u8UrlTestResult = 'video' } } document.addEventListener("securitypolicyviolation", onsecuritypolicyviolation) if (this.m3u8UrlTestResult != undefined) { return this.m3u8UrlTestResult; } function limitStream(stream, limit) { const reader = stream.getReader(); let bytesRead = 0; return new ReadableStream({ async pull(controller) { const { value, done } = await reader.read(); if (done || bytesRead >= limit) { controller.close(); return; } bytesRead += value.byteLength; controller.enqueue(value); }, cancel(reason) { reader.cancel(reason); } }); } return new Promise((res, rej) => { const rtnType = (tp) => { if (this.m3u8UrlTestResult == undefined) { this.m3u8UrlTestResult = tp } res(this.m3u8UrlTestResult) } const abortController = new AbortController(); VideoTogetherFetch(testUrl, { signal: abortController.signal }).then(response => { const contentType = response.headers.get('Content-Type') if (contentType.startsWith('video/')) { rtnType('video'); } const limitedStream = limitStream(response.body, 1024); // Limit to 1024 bytes return new Response(limitedStream, { headers: response.headers }); }).then(r => r.text()) .then(async txt => { abortController.abort(); if (isM3U8(txt)) { rtnType('m3u8'); } else { rtnType('video'); } }).catch(e => { if (testUrl.startsWith('blob')) { rtnType('unknown'); } else { rtnType('video'); } }).finally(() => { document.removeEventListener("securitypolicyviolation", onsecuritypolicyviolation) }) }) } // download GetAllM3u8SegUrls(m3u8Url) { for (let id in this.m3u8Files) { for (let mid in this.m3u8Files) { let m3u8 = this.m3u8Files if (m3u8Url == m3u8.m3u8Url) { return extractMediaUrls(m3u8.m3u8Content, m3u8.m3u8Url); } } } } // end of download UpdateStatusText(text, color) { if (window.self != window.top) { sendMessageToTop(MessageType.UpdateStatusText, { text: text + "", color: color }); } else { window.videoTogetherFlyPannel.UpdateStatusText(text + "", color); } } async processReceivedMessage(type, data, _msg) { let _this = this; // console.info("get ", type, window.location, data); switch (type) { case MessageType.CallScheduledTask: this.ScheduledTask(); break; case MessageType.ActivatedVideo: if (this.activatedVideo == undefined || this.activatedVideo.activatedTime{ if (video.VideoTogetherVideoId == data.video.id) { try { await this.SyncMasterVideo(data, video); } catch (e) { this.UpdateStatusText(e, "red"); } } }) this.sendMessageToSonWithContext(type, data); break; case MessageType.UpdateRoomRequest: let m3u8Url = undefined; try { let d = NaN; let selected = null; for (let id in this.m3u8Files) { this.m3u8Files.forEach(m3u8 => { // here m3u8Url may be empty, may caused by the new response // from limitedstream, but we have a new fetch after that, // so we can always get the correct url. if (isNaN(d) || Math.abs(data.duration - m3u8.duration) <= d) { d = Math.abs(data.duration - m3u8.duration); selected = m3u8; } return; }) } if (d < 3 || d / data.durationshow(windowPannel.easyShareCopyBtn)); } else { show(windowPannel.easyShareCopyBtn); } } if (!isEmpty(data.m3u8Url) && isEasyShareEnabled()) { this.currentM3u8Url = data.m3u8Url; showEasyShareCopyBtn(); } else { this.currentM3u8Url = undefined; if (isWeb()) { showEasyShareCopyBtn(); } else { hide(windowPannel.easyShareCopyBtn); } } } catch { }; try { await this.UpdateRoom(data.name, data.password, data.url, data.playbackRate, data.currentTime, data.paused, data.duration, data.localTimestamp, data.m3u8Url); if (this.waitForLoadding) { this.UpdateStatusText("wait for memeber loading", "red"); } else { _this.UpdateStatusText("Sync " + _this.GetDisplayTimeText(), "green"); } } catch (e) { this.UpdateStatusText(e, "red"); } break; case MessageType.SyncMemberVideo: this.ForEachVideo(async video => { if (video.VideoTogetherVideoId == data.video.id) { try { await this.SyncMemberVideo(data, video); } catch (e) { _this.UpdateStatusText(e, "red"); } } }) this.sendMessageToSonWithContext(type, data); break; case MessageType.GetRoomData: this.duration = data["duration"]; break; case MessageType.UpdateStatusText: window.videoTogetherFlyPannel.UpdateStatusText(data.text, data.color); break; case MessageType.JumpToNewPage: window.location = data.url; let currentUrl = new URL(window.location); let newUrl = new URL(data.url); if (newUrl.hash != "") { currentUrl.hash = ""; newUrl.hash = ""; if (currentUrl.href == newUrl.href) { extension.url = data.url; // window.location.reload();// for hash change } } break; case MessageType.ChangeVideoVolume: this.ForEachVideo(video => { video.volume = data.volume; }); this.sendMessageToSonWithContext(type, data); break; case MessageType.FetchResponse: { try { this.callbackMap.get(data.id)(data); } catch { }; break; } case MessageType.SyncStorageValue: { const firstSync = (window.VideoTogetherSettingEnabled == undefined) window.VideoTogetherStorage = data; if (!this.isMain) { return; } try { if (window.VideoTogetherStorage.PublicNextDownload.url == window.location.href && this.HasDownload != true) { const a = document.createElement("a"); a.href = window.VideoTogetherStorage.PublicNextDownload.url; a.download = window.VideoTogetherStorage.PublicNextDownload.filename; a.click(); this.HasDownload = true; } } catch { } try { if (!this.RecoveryStateFromTab) { this.RecoveryStateFromTab = true; this.RecoveryState() } } catch (e) { }; try { if (data.PublicMessageVoice != null) { windowPannel.voiceSelect.value = data.PublicMessageVoice; } } catch { }; if (!window.videoTogetherFlyPannel.disableDefaultSize && firstSync) { if (data.MinimiseDefault) { window.videoTogetherFlyPannel.Minimize(true); } else { window.videoTogetherFlyPannel.Maximize(true); } } if (typeof (data.PublicUserId) != 'string' || data.PublicUserId.length{ try { function calculateM3U8Duration(textContent) { let totalDuration = 0; const lines = textContent.split('\n'); for (let i = 0; i = lines.length || lines.startsWith('#')) { continue; } let durationLine = lines; let durationParts = durationLine.split(':'); if (durationParts.length > 1) { let durationValue = durationParts.split(','); let duration = parseFloat(durationValue); if (!isNaN(duration)) { totalDuration += duration; } } } } return totalDuration; } const cyrb53 = (str, seed = 0) => { let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; for (let i = 0, ch; i >> 16), 2246822507); h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909); h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507); h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909); return 4294967296 * (2097151 & h2) + (h1 >>> 0); }; if (m3u8.m3u8Url.startsWith("data:")) { m3u8.m3u8Url = `${cyrb53(m3u8.m3u8Url)}`; } if (this.m3u8DurationReCal == undefined) { this.m3u8DurationReCal = calculateM3U8Duration(m3u8.m3u8Content); } m3u8.duration = this.m3u8DurationReCal; } catch { } }) this.m3u8Files] = data['m3u8Files']; this.m3u8PostWindows] = _msg.source; break; } case MessageType.FetchRealUrlReq: { console.log(data); if (realUrlCache == undefined) { const controller = new AbortController(); let r = await Fetch(data.url, { method: "GET", signal: controller.signal }); controller.abort(); realUrlCache = r.url; } sendMessageToTop(MessageType.FetchRealUrlResp, { origin: data.origin, real: realUrlCache }); break; } case MessageType.FetchRealUrlResp: { console.log(data); WS.urlResp(data.origin, data.real); break; } case MessageType.FetchRealUrlFromIframeReq: { let real = await extension.FetchRemoteRealUrl(data.m3u8Url, data.idx, data.origin); sendMessageTo(_msg.source, MessageType.FetchRealUrlFromIframeResp, { origin: data.origin, real: real }); break; } case MessageType.FetchRealUrlFromIframeResp: { realUrlCache = data.real; break; } case MessageType.SendTxtMsg: { WS.sendTextMessage(data.currentSendingMsgId, data.value); break; } case MessageType.GotTxtMsg: { try { GotTxtMsgCallback(data.id, data.msg); } catch { }; this.sendMessageToSonWithContext(MessageType.GotTxtMsg, data); break; } case MessageType.ReadIndexedDbSw: { const result = await readFromIndexedDB(data.table, data.key); data.data = result navigator.serviceWorker.controller.postMessage({ source: "VideoTogether", type: 2012, data: data }); break; } case MessageType.StartDownload: { startDownload(data.m3u8Url, data.m3u8Content, data.urls, data.title, data.pageUrl); setInterval(() => { sendMessageToTop(MessageType.DownloadStatus, { downloadSpeedMb: this.downloadSpeedMb, downloadPercentage: this.downloadPercentage }) }, 1000) break; } case MessageType.DownloadStatus: { extension.downloadSpeedMb = data.downloadSpeedMb; extension.downloadPercentage = data.downloadPercentage; if (extension.downloadPercentage == 100) { if (this.downloadM3u8Completed != true) { this.downloadM3u8Completed = true; extension.Fetch(extension.video_together_host + "/beta/counter?key=download_m3u8_completed") } hide(select("#downloadingAlert")) show(select("#downloadCompleted")) } select("#downloadStatus").innerText = extension.downloadPercentage + "% " select("#downloadSpeed").innerText = extension.downloadSpeedMb.toFixed(2) + "MB/s" select("#downloadProgressBar").value = extension.downloadPercentage break; } default: // console.info("unhandled message:", type, data) break; } } openAllLinksInSelf() { let hrefs = document.getElementsByTagName("a"); for (let i = 0; i < hrefs.length; i++) { hrefs.target = "_self"; } } async RunWithRetry(func, count) { for (let i = 0; iel.addEventListener(e, fn, false)); } VideoClicked(e) { console.info("vide event: ", e.type); // maybe we need to check if the event is activated by user interaction this.setActivatedVideoDom(e.target); if (!isLimited()) { sendMessageToTop(MessageType.CallScheduledTask, {}); } } AddVideoListener(videoDom) { if (this.VideoClickedListener == undefined) { this.VideoClickedListener = this.VideoClicked.bind(this) } this.addListenerMulti(videoDom, "play pause seeked", this.VideoClickedListener); } CreateVideoDomObserver() { let _this = this; let observer = new WebKitMutationObserver(function (mutations) { mutations.forEach(function (mutation) { for (let i = 0; i_this.AddVideoListener(v)); } catch { } try { if (extension.isMain && window.VideoTogetherStorage.OpenAllLinksInSelf != false && _this.role != _this.RoleEnum.Null) { if (mutation.addedNodes.tagName == "A") { mutation.addedNodes.target = "_self"; } let links = mutation.addedNodes.getElementsByTagName("a"); for (let i = 0; i{ let videos = document.getElementsByTagName(vTag); for (let i = 0; i < videos.length; i++) { this.AddVideoListener(videos); } }) } getLocalTimestamp() { return Date.now() / 1000 + this.timeOffset; } async SyncTimeWithServer(url = null) { if (url == null) { url = this.video_together_host; } let startTime = Date.now() / 1000; let response = await this.Fetch(url + "/timestamp"); let endTime = Date.now() / 1000; let data = await this.CheckResponse(response); this.httpSucc = true this.video_together_host = url; this.UpdateTimestampIfneeded(data["timestamp"], startTime, endTime); sendMessageToTop(MessageType.SetStorageValue, { key: ";PublicVtVersion", value: data["vtVersion"] }); } RecoveryState() { function RecoveryStateFrom(getFunc) { let vtRole = getFunc("VideoTogetherRole"); let vtUrl = getFunc("VideoTogetherUrl"); let vtRoomName = getFunc("VideoTogetherRoomName"); let timestamp = parseFloat(getFunc("VideoTogetherTimestamp")); let password = getFunc("VideoTogetherPassword"); let voice = getFunc("VideoTogetherVoice"); if (timestamp + 60window.VideoTogetherStorage.VideoTogetherTabStorage); } catch { }; return; } let localTimestamp = window.sessionStorage.getItem("VideoTogetherTimestamp"); let urlTimestamp = url.searchParams.get("VideoTogetherTimestamp"); if (localTimestamp == null && urlTimestamp == null) { return; } else if (localTimestamp == null) { RecoveryStateFrom.bind(this)(key => url.searchParams.get(key)); } else if (urlTimestamp == null) { RecoveryStateFrom.bind(this)(key => window.sessionStorage.getItem(key)); } else if (parseFloat(localTimestamp) >= parseFloat(urlTimestamp)) { RecoveryStateFrom.bind(this)(key => window.sessionStorage.getItem(key)); } else { RecoveryStateFrom.bind(this)(key => url.searchParams.get(key)); } } async JoinRoom(name, password) { if (name == "") { popupError(";Please input room name") return; } try { this.tempUser = generateTempUserId(); this.roomName = name; this.password = password; this.setRole(this.RoleEnum.Member); window.videoTogetherFlyPannel.InRoom(); } catch (e) { this.UpdateStatusText(e, "red"); } } exitRoom() { this.voiceVolume = null; this.videoVolume = null; roomUuid = null; WS.disconnect(); Voice.stop(); show(select('#mainPannel')); hide(select('#voicePannel')); this.duration = undefined; window.videoTogetherFlyPannel.inputRoomName.value = ""; window.videoTogetherFlyPannel.inputRoomPassword.value = ""; this.roomName = ""; this.setRole(this.RoleEnum.Null); window.videoTogetherFlyPannel.InLobby(); let state = this.GetRoomState(""); sendMessageToTop(MessageType.SetTabStorage, state); this.SaveStateToSessionStorageWhenSameOrigin(""); } getVoiceVolume() { if (this.voiceVolume != null) { return this.voiceVolume; } try { if (window.VideoTogetherStorage.VideoTogetherTabStorage.VoiceVolume != null) { return window.VideoTogetherStorage.VideoTogetherTabStorage.VoiceVolume; } } catch { } return 100; } getVideoVolume() { if (this.videoVolume != null) { return this.videoVolume; } try { if (window.VideoTogetherStorage.VideoTogetherTabStorage.VideoVolume != null) { return window.VideoTogetherStorage.VideoTogetherTabStorage.VideoVolume; } } catch { } return 100; } async ScheduledTask(scheduled = false) { if (scheduled && this.lastScheduledTaskTs + 2 > Date.now() / 1000) { return; } this.lastScheduledTaskTs = Date.now() / 1000; try { if (this.isMain) { if (windowPannel.videoVolume.value != this.getVideoVolume()) { windowPannel.videoVolume.value = this.getVideoVolume() windowPannel.videoVolume.dispatchEvent(new Event('input', { bubbles: true })); } if (windowPannel.callVolumeSlider.value != this.getVoiceVolume()) { windowPannel.callVolumeSlider.value = this.getVoiceVolume(); windowPannel.callVolumeSlider.dispatchEvent(new Event('input', { bubbles: true })); } if (this.videoVolume != null) { sendMessageToTop(MessageType.ChangeVideoVolume, { volume: this.getVideoVolume() / 100 }); } [...select('#peer').querySelectorAll("*")].forEach(e => { e.volume = this.getVoiceVolume() / 100; }); } } catch { } try { await this.ForEachVideo(video => { if (video.VideoTogetherVideoId == undefined) { video.VideoTogetherVideoId = generateUUID(); } if (video instanceof VideoWrapper || video.VideoTogetherChoosed == true) { // ad hoc sendMessageToTop(MessageType.ReportVideo, new VideoModel(video.VideoTogetherVideoId, video.duration, 0, Date.now() / 1000, 1)); } else { sendMessageToTop(MessageType.ReportVideo, new VideoModel(video.VideoTogetherVideoId, video.duration, 0, Date.now() / 1000)); } }) this.videoMap.forEach((video, id, map) => { if (video.refreshTime + VIDEO_EXPIRED_SECOND{ if (this.minTrip == 1e9 || !this.httpSucc) { this.SyncTimeWithServer(this.video_together_backup_host); } }, 3000); } else { // TODO // if (this.video_together_host == this.video_together_backup_host) { // this.SyncTimeWithServer(this.video_together_main_host); // } } } catch { }; } try { switch (this.role) { case this.RoleEnum.Null: return; case this.RoleEnum.Master: { if (window.VideoTogetherStorage != undefined && window.VideoTogetherStorage.VideoTogetherTabStorageEnabled) { let state = this.GetRoomState(""); sendMessageToTop(MessageType.SetTabStorage, state); } this.SaveStateToSessionStorageWhenSameOrigin(""); let video = this.GetVideoDom(); if (video == undefined) { await this.UpdateRoom(this.roomName, this.password, this.linkWithoutState(window.location), 1, 0, true, 1e9, this.getLocalTimestamp()); throw new Error("No video in this page"); } else { sendMessageToTop(MessageType.SyncMasterVideo, { waitForLoadding: this.waitForLoadding, video: video, password: this.password, roomName: this.roomName, link: this.linkWithoutState(window.location) }); } break; } case this.RoleEnum.Member: { let room = await this.GetRoom(this.roomName, this.password); sendMessageToTop(MessageType.RoomDataNotification, room); this.duration = room["duration"]; let newUrl = room["url"]; if (isEasyShareMember()) { if (isEmpty(room['m3u8Url'])) { throw new Error("Can't sync this video"); } else { let _url = new URL(window.location); _url.hash = room['m3u8Url']; newUrl = _url.href; window.VideoTogetherEasyShareUrl = room['url']; window.VideoTogetherEasyShareTitle = room['videoTitle']; } } if (newUrl != this.url && (window.VideoTogetherStorage == undefined || !window.VideoTogetherStorage.DisableRedirectJoin)) { if (window.VideoTogetherStorage != undefined && window.VideoTogetherStorage.VideoTogetherTabStorageEnabled) { let state = this.GetRoomState(newUrl); sendMessageToTop(MessageType.SetTabStorage, state); setInterval(() => { if (window.VideoTogetherStorage.VideoTogetherTabStorage.VideoTogetherUrl == newUrl) { try { if (isWeb()) { if (!this._jumping && window.location.origin != (new URL(newUrl).origin)) { this._jumping = true; alert(";Please join again after jump"); } } } catch { }; this.SetTabStorageSuccessCallback = () => { sendMessageToTop(MessageType.JumpToNewPage, { url: newUrl }); this.SetTabStorageSuccessCallback = () => { }; } } }, 200); } else { if (this.SaveStateToSessionStorageWhenSameOrigin(newUrl)) { sendMessageToTop(MessageType.JumpToNewPage, { url: newUrl }); } else { sendMessageToTop(MessageType.JumpToNewPage, { url: this.linkWithMemberState(newUrl).toString() }); } } } else { let state = this.GetRoomState(""); sendMessageToTop(MessageType.SetTabStorage, state); } if (this.PlayAdNow()) { throw new Error(";Playing AD"); } let video = this.GetVideoDom(); if (video == undefined) { throw new Error("No video in this page"); } else { sendMessageToTop(MessageType.SyncMemberVideo, { video: this.GetVideoDom(), roomName: this.roomName, password: this.password, room: room }) } break; } } } catch (e) { this.UpdateStatusText(e, "red"); } } PlayAdNow() { try { // iqiyi if (window.location.hostname.endsWith('iqiyi.com')) { let cdTimes = document.querySelectorAll('.cd-time'); for (let i = 0; i < cdTimes.length; i++) { if (cdTimes.offsetParent != null) { return true; } } } } catch { } try { if (window.location.hostname.endsWith('v.qq.com')) { let adCtrls = document.querySelectorAll('.txp_ad_control:not(.txp_none)'); for (let i = 0; i{ if (video.priority > 0) { highPriorityVideo = video; } }) if (highPriorityVideo != undefined) { return highPriorityVideo; } if (this.role == this.RoleEnum.Master && this.activatedVideo != undefined && this.videoMap.get(this.activatedVideo.id) != undefined && this.videoMap.get(this.activatedVideo.id).refreshTime + VIDEO_EXPIRED_SECOND >= Date.now() / 1000) { // do we need use this rule for member role? when multi closest videos? // return this.activatedVideo; } // get the longest video for master const _duration = this.duration == undefined ? 1e9 : this.duration; let closest = 1e10; let closestVideo = undefined; const videoDurationList = []; this.videoMap.forEach((video, id) => { try { if (!isFinite(video.duration)) { return; } videoDurationList.push(video.duration); if (closestVideo == undefined) { closestVideo = video; } if (Math.abs(video.duration - _duration)0 && videoDom.currentTime{ if (r == 'm3u8' && this.hasCheckedM3u8Url != true) { fetch(nativeSrc).then(r => r.text()).then(m3u8Content => { if (isMasterM3u8(m3u8Content)) { const mediaM3u8Url = getFirstMediaM3U8(m3u8Content, nativeSrc); fetch(mediaM3u8Url).then(r => r.text()).then(() => { this.hasCheckedM3u8Url = true; }) } else { this.hasCheckedM3u8Url = true; } } ) } }) m3u8UrlType = this.m3u8UrlTestResult } catch { }; sendMessageToTop(MessageType.UpdateRoomRequest, { name: data.roomName, password: data.password, url: data.link, playbackRate: videoDom.playbackRate, currentTime: videoDom.currentTime, paused: paused, duration: videoDom.duration, localTimestamp: this.getLocalTimestamp(), m3u8Url: m3u8Url, m3u8UrlType: m3u8UrlType }) } linkWithoutState(link) { let url = new URL(link); url.searchParams.delete("VideoTogetherUrl"); url.searchParams.delete("VideoTogetherRoomName"); url.searchParams.delete("VideoTogetherRole"); url.searchParams.delete("VideoTogetherPassword"); url.searchParams.delete("VideoTogetherTimestamp"); return url.toString(); } GetRoomState(link) { if (inDownload) { return {}; } if (this.role == this.RoleEnum.Null) { return {}; } let voice = Voice.status; if (voice == VoiceStatus.CONNECTTING) { try { voice = window.VideoTogetherStorage.VideoTogetherTabStorage.VideoTogetherVoice; } catch { voice = VoiceStatus.STOP; } } return { VideoTogetherUrl: link, VideoTogetherRoomName: this.roomName, VideoTogetherPassword: this.password, VideoTogetherRole: this.role, VideoTogetherTimestamp: Date.now() / 1000, VideoTogetherVoice: voice, VideoVolume: this.getVideoVolume(), VoiceVolume: this.getVoiceVolume() } } SaveStateToSessionStorageWhenSameOrigin(link) { if (inDownload) { return false; } try { let sameOrigin = false; if (link != "") { let url = new URL(link); let currentUrl = new URL(window.location); sameOrigin = (url.origin == currentUrl.origin); } if (link == "" || sameOrigin) { window.sessionStorage.setItem("VideoTogetherUrl", link); window.sessionStorage.setItem("VideoTogetherRoomName", this.roomName); window.sessionStorage.setItem("VideoTogetherPassword", this.password); window.sessionStorage.setItem("VideoTogetherRole", this.role); window.sessionStorage.setItem("VideoTogetherTimestamp", Date.now() / 1000); return sameOrigin; } else { return false; } } catch (e) { console.error(e); } } linkWithMemberState(link, newRole = undefined, expire = true) { let url = new URL(link); let tmpSearch = url.search; url.search = ""; url.searchParams.set("VideoTogetherUrl", link); url.searchParams.set("VideoTogetherRoomName", this.roomName); url.searchParams.set("VideoTogetherPassword", this.password); url.searchParams.set("VideoTogetherRole", newRole ? newRole : this.role); url.searchParams.set("VideoTogetherTimestamp", expire ? Date.now() / 1000 : 1e10); let urlStr = url.toString(); if (tmpSearch.length > 1) { urlStr = urlStr + "&" + tmpSearch.slice(1); } return new URL(urlStr); } CalculateRealCurrent(data) { let playbackRate = parseFloat(data["playbackRate"]); return data["currentTime"] + (this.getLocalTimestamp() - data["lastUpdateClientTime"]) * (isNaN(playbackRate) ? 1 : playbackRate); } GetDisplayTimeText() { let date = new Date(); return date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds(); } async SyncMemberVideo(data, videoDom) { try { if (this.isMain) { useMobileStyle(videoDom); } } catch { } if (this.lastSyncMemberVideo + 1 > Date.now() / 1000) { return; } this.lastSyncMemberVideo = Date.now() / 1000; let room = data.room; sendMessageToTop(MessageType.GetRoomData, room); // useless this.duration = room["duration"]; // useless if (videoDom == undefined) { throw new Error("没有视频"); } const waitForLoadding = room['waitForLoadding']; let paused = room['paused']; if (waitForLoadding && !paused && !Var.isThisMemberLoading) { paused = true; } let isLoading = (Math.abs(this.memberLastSeek - videoDom.currentTime)1) { videoDom.currentTime = this.CalculateRealCurrent(room); } // play fail will return so here is safe this.memberLastSeek = videoDom.currentTime; } else { videoDom.videoTogetherPaused = true; if (Math.abs(videoDom.currentTime - room["currentTime"]) > 0.1) { videoDom.currentTime = room["currentTime"]; } } if (videoDom.paused != paused) { if (paused) { console.info("pause"); videoDom.pause(); } else { try { console.info("play"); { // check if the video is ready if (window.location.hostname.endsWith('aliyundrive.com')) { if (videoDom.readyState == 0) { throw new Error("Need to play manually"); } } } await videoDom.play(); if (videoDom.paused) { throw new Error("Need to play manually"); } } catch (e) { throw new Error("Need to play manually"); } } } if (videoDom.playbackRate != room["playbackRate"]) { try { videoDom.playbackRate = parseFloat(room["playbackRate"]); } catch (e) { } } if (isNaN(videoDom.duration)) { throw new Error("Need to play manually"); } sendMessageToTop(MessageType.UpdateStatusText, { text: "Sync " + this.GetDisplayTimeText(), color: "green" }); setTimeout(() => { try { if (Math.abs(room["duration"] - videoDom.duration)await this.UpdateRoom(name, password, url, 1, 0, true, 0, this.getLocalTimestamp()), 2); this.setRole(this.RoleEnum.Master); this.roomName = name; this.password = password; window.videoTogetherFlyPannel.InRoom(); } catch (e) { this.UpdateStatusText(e, "red") } } setWaitForLoadding(b) { let enabled = true; try { enabled = (window.VideoTogetherStorage.WaitForLoadding != false) } catch { } this.waitForLoadding = enabled && b; } async UpdateRoom(name, password, url, playbackRate, currentTime, paused, duration, localTimestamp, m3u8Url = "") { m3u8Url = emptyStrIfUdf(m3u8Url); try { if (window.location.pathname == "/page") { let url = new URL(atob(new URL(window.location).searchParams.get("url"))); window.location = url; } } catch { } WS.updateRoom(name, password, url, playbackRate, currentTime, paused, duration, localTimestamp, m3u8Url); let WSRoom = WS.getRoom(); if (WSRoom != null) { this.setWaitForLoadding(WSRoom['waitForLoadding']); sendMessageToTop(MessageType.RoomDataNotification, WSRoom); return WSRoom; } let apiUrl = new URL(this.video_together_host + "/room/update"); apiUrl.searchParams.set("name", name); apiUrl.searchParams.set("password", password); apiUrl.searchParams.set("playbackRate", playbackRate); apiUrl.searchParams.set("currentTime", currentTime); apiUrl.searchParams.set("paused", paused); apiUrl.searchParams.set("url", url); apiUrl.searchParams.set("lastUpdateClientTime", localTimestamp); apiUrl.searchParams.set("duration", duration); apiUrl.searchParams.set("tempUser", this.tempUser); apiUrl.searchParams.set("protected", isRoomProtected()); apiUrl.searchParams.set("videoTitle", this.isMain ? document.title : this.videoTitle); apiUrl.searchParams.set("m3u8Url", emptyStrIfUdf(m3u8Url)); let startTime = Date.now() / 1000; let response = await this.Fetch(apiUrl); let endTime = Date.now() / 1000; let data = await this.CheckResponse(response); sendMessageToTop(MessageType.RoomDataNotification, data); this.UpdateTimestampIfneeded(data["timestamp"], startTime, endTime); return data; } async UpdateTimestampIfneeded(serverTimestamp, startTime, endTime) { if (typeof serverTimestamp == 'number' && typeof startTime == 'number' && typeof endTime == 'number') { if (endTime - startTime
dakenaid
发表于 2024-10-6 12:33
11111111111111111
peternewone
发表于 2024-10-6 12:33
66666666666
愤怒的汤姆猫
发表于 2024-10-6 12:33
奥术大师多 王企鹅趣味sad阿萨德
半宅男
发表于 2024-10-6 12:33
什么都没:)