UNPKG

@scrypted/reolink

Version:

Reolink Plugin for Scrypted

2 lines 372 kB
/*! For license information please see main.nodejs.js.LICENSE.txt */ (()=>{var e={18:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.OnvifCameraAPI=t.OnvifEvent=void 0,t.connectCameraAPI=async function(e,t,n,i,r){const o=e.split(":"),[a,l]=o,p=await c((e=>{const i=new s({hostname:a,username:t,password:n,port:l},(t=>e(t,i)))}));return new u(p,t,n,i,r)};const i=n(1251),r=n(4434),o=n(2952),{Cam:s}=o;var a;async function c(e){return new Promise(((t,n)=>{e(((e,i)=>{if(e)return n(e);t(i)}))}))}!function(e){e[e.MotionBuggy=0]="MotionBuggy",e[e.MotionStart=1]="MotionStart",e[e.MotionStop=2]="MotionStop",e[e.AudioStart=3]="AudioStart",e[e.AudioStop=4]="AudioStop",e[e.BinaryStart=5]="BinaryStart",e[e.BinaryStop=6]="BinaryStop",e[e.CellMotion=7]="CellMotion",e[e.Detection=8]="Detection",e[e.BinaryRingEvent=9]="BinaryRingEvent",e[e.DigitalInputStart=10]="DigitalInputStart",e[e.DigitalInputStop=11]="DigitalInputStop"}(a||(t.OnvifEvent=a={}));class u{constructor(e,t,n,i,r){this.cam=e,this.console=i,this.snapshotUrls=new Map,this.rtspUrls=new Map,this.binaryStateEvent=r,this.credential={username:t,password:n}}async request(e,t){return await(0,i.authHttpFetch)({..."string"==typeof e||e instanceof URL?{url:e}:e,rejectUnauthorized:!1,credential:this.credential,body:t})}async reboot(){return new Promise(((e,t)=>{this.cam.systemReboot(((n,i,r)=>{if(n)return this.console.log("reboot error",n),t(n);e(i)}))}))}listenEvents(){const e=new r.EventEmitter;return this.cam.on("event",((t,n)=>{if(e.emit("data",n),!t.message.message.data?.simpleItem?.$)return;const i=t.message.message.data.simpleItem.$.Value,r=function(e){let t="",n=e.split("/");for(let e=0;e<n.length;e++){let i=n[e].split(":").pop();0===t.length?t+=i:t+="/"+i}return t}(t.topic._);if(e.emit("onvifEvent",r,i),r.includes("MotionAlarm"))i?e.emit("event",a.MotionStart):e.emit("event",a.MotionStop);else if(r.includes("DetectedSound"))i?e.emit("event",a.AudioStart):e.emit("event",a.AudioStop);else if(!r.includes("Visitor")||!0!==i&&!1!==i){if(r.includes("VideoSource/Alarm"))"Ring"!==i&&"CameraBellButton"!==i||e.emit("event",a.BinaryRingEvent);else if(this.binaryStateEvent&&r.includes(this.binaryStateEvent))i?e.emit("event",a.BinaryStart):e.emit("event",a.BinaryStop);else if(r.includes("RuleEngine/CellMotionDetector/Motion"))"IsMotion"===t.message.message.data.simpleItem.$.Name&&i&&e.emit("event",a.MotionBuggy);else if(r.includes("RuleEngine/ObjectDetector")&&i)try{const n=t.message.message.data.simpleItem.$.Name,i=this.detections.get(n);this.console.log("object detected:",i),e.emit("event",a.Detection,i)}catch(e){this.console.warn("error parsing detection",e)}}else i?e.emit("event",a.BinaryStart):e.emit("event",a.BinaryStop)})),e}async canConfigureEncoding(){return!!(await c((e=>this.cam.getMediaServiceCapabilities(e)))).profileCapabilities}async getVideoEncoderConfigurationOptions(e,t){const n=await c((t=>this.cam.getVideoEncoderConfigurationOptions({profileToken:e},t))),i=[];let r;n.H264&&i.push("h264"),n.H265&&i.push("h265");const o=[];let s,a;const u=[];let l;const p=e=>Array.isArray(e)?e:[e],d=n?.extension?.H264||n?.H264;return d&&(d?.H264ProfilesSupported&&u.push(...p(d.H264ProfilesSupported).map((e=>e.toLowerCase()))),d?.resolutionsAvailable&&o.push(...p(d.resolutionsAvailable).map((e=>[e.width,e.height]))),(d?.frameRateRange?.min||d?.frameRateRange?.max)&&(s=[d.frameRateRange.min,d.frameRateRange.max]),(d?.govLengthRange?.min||d?.govLengthRange?.max)&&(a=[d.govLengthRange.min,d.govLengthRange.max]),(d?.bitrateRange?.min||d?.bitrateRange?.max)&&(l=[d.bitrateRange.min,d.bitrateRange.max])),(n.qualityRange?.min||n?.qualityRange?.max)&&(r=[n.qualityRange.min,n.qualityRange.max]),{codecs:i,qualityRange:r,fpsRange:s,keyframeIntervalRange:a,resolutions:o,profiles:u,bitrateRange:l}}async setVideoEncoderConfiguration(e){return c((t=>this.cam.setVideoEncoderConfiguration(e,t)))}async setAudioEncoderConfiguration(e){return c((t=>this.cam.setAudioEncoderConfiguration(e,t)))}async getProfiles(){return this.profiles||(this.profiles=c((e=>this.cam.getProfiles(e))),this.profiles.catch((()=>this.profiles=void 0))),this.profiles}async getMainProfileToken(){const e=await this.getProfiles(),{token:t}=e[0].$;return t}async supportsEvents(){return new Promise(((e,t)=>{this.cam.getCapabilities(((n,i,r)=>{if(n)return this.console.log("supportsEvents error",n),t(n);!n&&i.events&&i.events.WSPullPointSupport&&!0===i.events.WSPullPointSupport?this.console.log("Camera supports WSPullPoint",r):this.console.log("Camera does not show WSPullPoint support, but trying anyway",r),e(void 0)}))}))}async createSubscription(){return new Promise(((e,t)=>{this.cam.createPullPointSubscription(((n,i,r)=>{if(n)return this.console.log("createSubscription error",n),t(n);e(void 0)}))}))}unsubscribe(){return new Promise(((e,t)=>{this.cam.unsubscribe(((n,i,r)=>{if(n)return this.console.log("unsubscribe error",n),t(n);e(void 0)}))}))}async getEventTypes(){return this.detections?[...this.detections.values()]:new Promise(((e,t)=>{this.cam.getEventProperties(((n,i,r)=>{if(n)return this.console.log("getEventTypes error",n),t(n);this.console.log(r),this.detections=new Map;try{if(i.topicSet.ruleEngine.objectDetector)for(const[e,t]of Object.entries(i.topicSet.ruleEngine.objectDetector))try{const n=t.messageDescription.data.simpleItemDescription.$.Name;this.detections.set(n,e)}catch(e){}}catch(e){}e([...this.detections.values()])}))}))}async getStreamUrl(e){if(e||(e=await this.getMainProfileToken()),!this.rtspUrls.has(e)){const t=(await c((t=>this.cam.getStreamUri({protocol:"RTSP",profileToken:e},t)))).uri;this.rtspUrls.set(e,t)}return this.rtspUrls.get(e)}async jpegSnapshot(e,t=1e4){if(e||(e=await this.getMainProfileToken()),!this.snapshotUrls.has(e))try{const t=(await c((t=>this.cam.getSnapshotUri({profileToken:e},t)))).uri;this.snapshotUrls.set(e,t)}catch(t){if(!t.message||-1===t.message.indexOf("ActionNotSupported"))throw t;this.snapshotUrls.set(e,void 0)}const n=this.snapshotUrls.get(e);if(!n)return;return(await this.request({url:n,timeout:t})).body}getDeviceInformation(){return c((e=>{this.cam.getDeviceInformation(e)}))}async getOSDs(){return c((e=>{this.cam.getOSDs(e)}))}async setOSD(e){return c((t=>{this.cam.setOSD(e,t)}))}}t.OnvifCameraAPI=u},66:function(e,t){(function(){t.defaults={.1:{explicitCharkey:!1,trim:!0,normalize:!0,normalizeTags:!1,attrkey:"@",charkey:"#",explicitArray:!1,ignoreAttrs:!1,mergeAttrs:!1,explicitRoot:!1,validator:null,xmlns:!1,explicitChildren:!1,childkey:"@@",charsAsChildren:!1,includeWhiteChars:!1,async:!1,strict:!0,attrNameProcessors:null,attrValueProcessors:null,tagNameProcessors:null,valueProcessors:null,emptyTag:""},.2:{explicitCharkey:!1,trim:!1,normalize:!1,normalizeTags:!1,attrkey:"$",charkey:"_",explicitArray:!0,ignoreAttrs:!1,mergeAttrs:!1,explicitRoot:!0,validator:null,xmlns:!1,explicitChildren:!1,preserveChildrenOrder:!1,childkey:"$$",charsAsChildren:!1,includeWhiteChars:!1,async:!1,strict:!0,attrNameProcessors:null,attrValueProcessors:null,tagNameProcessors:null,valueProcessors:null,rootName:"root",xmldec:{version:"1.0",encoding:"UTF-8",standalone:!0},doctype:null,renderOpts:{pretty:!0,indent:" ",newline:"\n"},headless:!1,chunkSize:1e4,emptyTag:"",cdata:!1}}}).call(this)},148:(e,t,n)=>{const i=n(2018),r=n(9023);t.init=function(e){e.inspectOpts={};const n=Object.keys(t.inspectOpts);for(let i=0;i<n.length;i++)e.inspectOpts[n[i]]=t.inspectOpts[n[i]]},t.log=function(...e){return process.stderr.write(r.format(...e)+"\n")},t.formatArgs=function(n){const{namespace:i,useColors:r}=this;if(r){const t=this.color,r="[3"+(t<8?t:"8;5;"+t),o=` ${r};1m${i} `;n[0]=o+n[0].split("\n").join("\n"+o),n.push(r+"m+"+e.exports.humanize(this.diff)+"")}else n[0]=function(){if(t.inspectOpts.hideDate)return"";return(new Date).toISOString()+" "}()+i+" "+n[0]},t.save=function(e){e?process.env.DEBUG=e:delete process.env.DEBUG},t.load=function(){return process.env.DEBUG},t.useColors=function(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):i.isatty(process.stderr.fd)},t.destroy=r.deprecate((()=>{}),"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."),t.colors=[6,2,3,4,5,1];try{const e=n(Object(function(){var e=new Error("Cannot find module 'supports-color'");throw e.code="MODULE_NOT_FOUND",e}()));e&&(e.stderr||e).level>=2&&(t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const n=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let i=process.env[t];return i=!!/^(yes|on|true|enabled)$/i.test(i)||!/^(no|off|false|disabled)$/i.test(i)&&("null"===i?null:Number(i)),e[n]=i,e}),{}),e.exports=n(5729)(t);const{formatters:o}=e.exports;o.o=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts).split("\n").map((e=>e.trim())).join(" ")},o.O=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts)}},314:(e,t,n)=>{const i=n(2018),r=n(9023);t.init=function(e){e.inspectOpts={};const n=Object.keys(t.inspectOpts);for(let i=0;i<n.length;i++)e.inspectOpts[n[i]]=t.inspectOpts[n[i]]},t.log=function(...e){return process.stderr.write(r.formatWithOptions(t.inspectOpts,...e)+"\n")},t.formatArgs=function(n){const{namespace:i,useColors:r}=this;if(r){const t=this.color,r="[3"+(t<8?t:"8;5;"+t),o=` ${r};1m${i} `;n[0]=o+n[0].split("\n").join("\n"+o),n.push(r+"m+"+e.exports.humanize(this.diff)+"")}else n[0]=function(){if(t.inspectOpts.hideDate)return"";return(new Date).toISOString()+" "}()+i+" "+n[0]},t.save=function(e){e?process.env.DEBUG=e:delete process.env.DEBUG},t.load=function(){return process.env.DEBUG},t.useColors=function(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):i.isatty(process.stderr.fd)},t.destroy=r.deprecate((()=>{}),"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."),t.colors=[6,2,3,4,5,1];try{const e=n(932);e&&(e.stderr||e).level>=2&&(t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221])}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const n=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let i=process.env[t];return i=!!/^(yes|on|true|enabled)$/i.test(i)||!/^(no|off|false|disabled)$/i.test(i)&&("null"===i?null:Number(i)),e[n]=i,e}),{}),e.exports=n(2887)(t);const{formatters:o}=e.exports;o.o=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts).split("\n").map((e=>e.trim())).join(" ")},o.O=function(e){return this.inspectOpts.colors=this.useColors,r.inspect(e,this.inspectOpts)}},336:function(e,t,n){"use strict";var i,r=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,r)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),s=this&&this.__importStar||(i=function(e){return i=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},i(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=i(e),s=0;s<n.length;s++)"default"!==n[s]&&r(t,e,n[s]);return o(t,e),t}),a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(t,"__esModule",{value:!0}),t.RtspServer=t.RtspClient=t.RtspBase=t.RtspStatusError=t.H265_NAL_TYPE_SEI_SUFFIX=t.H265_NAL_TYPE_SEI_PREFIX=t.H265_NAL_TYPE_FU=t.H265_NAL_TYPE_CRA_NUT=t.H265_NAL_TYPE_IDR_N_LP=t.H265_NAL_TYPE_IDR_W_RADL=t.H265_NAL_TYPE_BLA_N_LP=t.H265_NAL_TYPE_BLA_W_RADL=t.H265_NAL_TYPE_BLA_W_LP=t.H265_NAL_TYPE_PPS=t.H265_NAL_TYPE_SPS=t.H265_NAL_TYPE_VPS=t.H265_NAL_TYPE_AGG=t.H264_NAL_TYPE_MTAP32=t.H264_NAL_TYPE_MTAP16=t.H264_NAL_TYPE_FU_B=t.H264_NAL_TYPE_FU_A=t.H264_NAL_TYPE_STAP_B=t.H264_NAL_TYPE_STAP_A=t.H264_NAL_TYPE_PPS=t.H264_NAL_TYPE_SPS=t.H264_NAL_TYPE_SEI=t.H264_NAL_TYPE_IDR=t.H264_NAL_TYPE_RESERVED31=t.H264_NAL_TYPE_RESERVED30=t.H264_NAL_TYPE_RESERVED0=t.RTSP_FRAME_MAGIC=void 0,t.readMessage=b,t.readBody=S,t.writeMessage=T,t.findH264NaluType=function(e,t){if("h264"!==e.type)return;return P(e.chunks[e.chunks.length-1].subarray(12),t)},t.findH265NaluType=function(e,t){if("h265"!==e.type)return;return E(e.chunks[e.chunks.length-1].subarray(12),t)},t.parseH264NaluType=_,t.findH264NaluTypeInNalu=P,t.findH265NaluTypeInNalu=E,t.getStartedH264NaluTypes=O,t.getNaluTypesInNalu=I,t.getStartedH265NaluTypes=D,t.getNaluTypesInH265Nalu=x,t.isH265KeyFrameRelatedInSet=A,t.createRtspParser=function(e){let n;return{container:"rtsp",tcpProtocol:"rtsp://127.0.0.1/"+(0,c.randomBytes)(8).toString("hex"),inputArguments:["-rtsp_transport","tcp"],outputArguments:["-rtsp_transport","tcp",...e?.vcodec||[],...e?.acodec||[],"-pkt_size","32000","-f","rtsp"],findSyncFrame(e){for(let n=0;n<e.length;n++){const i=e[n];if("h264"===i.type){const r=O(i);if(r.has(t.H264_NAL_TYPE_SPS)||r.has(t.H264_NAL_TYPE_IDR))return e.slice(n)}else if("h265"===i.type){if(A(D(i)))return e.slice(n)}}},sdp:new Promise((e=>n=e)),async*parse(e,t,i){const r=new F(e);await r.handleSetup(),n(r.sdp);for await(const{type:e,rtcp:n,header:o,packet:s}of r.handleRecord())yield{chunks:[o,s],type:`${n?"rtcp-":""}${e}`,width:t,height:i}}}},t.parseHeaders=R,t.getFirstAuthenticateHeader=k,t.parseSemicolonDelimited=N,t.listenSingleRtspClient=async function(e){const t=e?.pathToken||c.default.randomBytes(8).toString("hex");let{url:n,clientPromise:i,server:r}=await(0,f.listenZeroSingleClient)(e?.hostname);const o="/"+t;n=n.replace("tcp:","rtsp:")+o;const s=i.then((t=>{const n=(e?.createServer||(e=>new F(e)))(t);return n.checkRequest=async(e,t,i,r)=>{n.checkRequest=void 0;return new d.URL(t).pathname===o},n}));return{url:n,rtspServerPromise:s,server:r}};const c=s(n(6982)),u=n(4434),l=a(n(9278)),p=a(n(4756)),d=n(7016),h=n(3290),f=n(3515),m=n(488),g=n(8460),y=n(4890),v=n(7724),w=["realm","nonce"];async function b(e){let t=[];for(;;){let n=await(0,g.readLine)(e);if(n=n.trim(),!n)return t;t.push(n)}}async function S(e,t){const n=parseInt(t["content-length"]);if(n)return(0,g.readLength)(e,n)}function T(e,t,n,i,r){let o=void 0!==t?`${t}\r\n`:"";n&&(i["Content-Length"]=n.length.toString());for(const[e,t]of Object.entries(i))o+=`${e}: ${t}\r\n`;o+="\r\n",e.write(o),r?.log("rtsp outgoing message\n",o),r?.log(),n&&e.write(n)}function _(e){return 31&e}function P(e,n){const i=_(e[0]);if(i===t.H264_NAL_TYPE_STAP_A){let t=1;for(;t<e.length;){const i=e.readUInt16BE(t);t+=2;if(_(e[t])===n)return e.subarray(t,t+i);t+=i}}else if(i===t.H264_NAL_TYPE_FU_A){const t=_(e[1]),i=!!(128&e[1]);if(t===n&&i)return e.subarray(1)}else if(i===n)return e}function C(e){return(126&e)>>1}function E(e,n){const i=C(e[0]);if(i===t.H265_NAL_TYPE_AGG){let t=1;for(;t<e.length;){const i=e.readUInt16BE(t);t+=2;if(C(e[t])===n)return e.subarray(t,t+i);t+=i}}else if(i===n)return e}function O(e){return"h264"!==e.type?new Set:I(e.chunks[e.chunks.length-1].subarray(12),!0)}function I(e,n=!1,i=!1){const r=new Set,o=_(e[0]);if(o===t.H264_NAL_TYPE_STAP_A){r.add(t.H264_NAL_TYPE_STAP_A);let n=1;for(;n<e.length;){const t=e.readUInt16BE(n);n+=2;const i=_(e[n]);r.add(i),n+=t}}else if(o===t.H264_NAL_TYPE_FU_A){r.add(t.H264_NAL_TYPE_FU_A);const o=_(e[1]);if(n){!!(128&e[1])&&r.add(o)}else if(i){!!(64&e[1])&&r.add(o)}else r.add(o)}else r.add(o);return r}function D(e){return"h265"!==e.type?new Set:x(e.chunks[e.chunks.length-1].subarray(12),!0)}function x(e,n=!1,i=!1){const r=new Set,o=C(e[0]);if(o===t.H265_NAL_TYPE_AGG){r.add(t.H265_NAL_TYPE_AGG);let n=2;for(;n<e.length;){const t=e.readUInt16BE(n);n+=2;const i=C(e[n]);r.add(i),n+=t}}else if(o===t.H265_NAL_TYPE_FU){r.add(t.H265_NAL_TYPE_FU);const o=63&e[2];if(n){!!(128&e[2])&&r.add(o)}else if(i){!!(64&e[2])&&r.add(o)}else r.add(o)}else r.add(o);return r}function A(e,n=!0){return!!(e.has(t.H265_NAL_TYPE_IDR_N_LP)||e.has(t.H265_NAL_TYPE_IDR_W_RADL)||e.has(t.H265_NAL_TYPE_CRA_NUT)||e.has(t.H265_NAL_TYPE_BLA_N_LP)||e.has(t.H265_NAL_TYPE_BLA_W_LP)||e.has(t.H265_NAL_TYPE_BLA_W_RADL))||!(!n||!(e.has(t.H265_NAL_TYPE_VPS)||e.has(t.H265_NAL_TYPE_SPS)||e.has(t.H265_NAL_TYPE_PPS)))}function R(e){const t={};for(const n of e.slice(1)){const e=n.indexOf(":");let i="";-1!==e&&(i=n.substring(e+1).trim());t[n.substring(0,e).toLowerCase()]=i}return t}function k(e){for(const t of e.slice(1)){const e=t.indexOf(":");let n="";-1!==e&&(n=t.substring(e+1).trim());if("www-authenticate"===t.substring(0,e).toLowerCase())return n}}function N(e){const t={};for(const n of e.split(";")){const[e,i]=n.split("=",2);t[e]=i}return t}t.RTSP_FRAME_MAGIC=36,t.H264_NAL_TYPE_RESERVED0=0,t.H264_NAL_TYPE_RESERVED30=30,t.H264_NAL_TYPE_RESERVED31=31,t.H264_NAL_TYPE_IDR=5,t.H264_NAL_TYPE_SEI=6,t.H264_NAL_TYPE_SPS=7,t.H264_NAL_TYPE_PPS=8,t.H264_NAL_TYPE_STAP_A=24,t.H264_NAL_TYPE_STAP_B=25,t.H264_NAL_TYPE_FU_A=28,t.H264_NAL_TYPE_FU_B=29,t.H264_NAL_TYPE_MTAP16=26,t.H264_NAL_TYPE_MTAP32=27,t.H265_NAL_TYPE_AGG=48,t.H265_NAL_TYPE_VPS=32,t.H265_NAL_TYPE_SPS=33,t.H265_NAL_TYPE_PPS=34,t.H265_NAL_TYPE_BLA_W_LP=16,t.H265_NAL_TYPE_BLA_W_RADL=17,t.H265_NAL_TYPE_BLA_N_LP=18,t.H265_NAL_TYPE_IDR_W_RADL=19,t.H265_NAL_TYPE_IDR_N_LP=20,t.H265_NAL_TYPE_CRA_NUT=21,t.H265_NAL_TYPE_FU=49,t.H265_NAL_TYPE_SEI_PREFIX=39,t.H265_NAL_TYPE_SEI_SUFFIX=40;class L extends Error{constructor(e){super(`RTSP Error: ${e.line}`),this.status=e}}t.RtspStatusError=L;class M{constructor(){}write(e,t,n){T(this.client,e,n,t,this.console)}async readMessage(){const e=await b(this.client);return this.console?.log("rtsp incoming message\n",e.join("\n")),this.console?.log(),e}}t.RtspBase=M;t.RtspClient=class extends M{constructor(e){super(),this.url=e,this.cseq=0,this.needKeepAlive=!1,this.setupOptions=new Map,this.issuedTeardown=!1,this.hasGetParameter=!0;const t=new d.URL(e),n=parseInt(t.port)||554;e.startsWith("rtsps")?this.client=p.default.connect({rejectUnauthorized:!1,port:n,host:t.hostname}):this.client=l.default.connect(n,t.hostname),this.client.on("error",(e=>{this.console?.log("client error",e)}))}async safeTeardown(){if(!this.issuedTeardown){this.issuedTeardown=!0;try{this.writeTeardown(),await(0,v.sleep)(500)}catch(e){}finally{this.client.destroy()}}}async writeRequest(e,t,n,i){let r;t=t||{},n?n.includes("rtsp://")||n.includes("rtsps://")||"*"===n?r=n:(r=this.contentBase||this.url,r+=(r.endsWith("/")?"":"/")+n):r=this.url;const o=new d.URL(r);o.username="",o.password="";const s=`${e} ${o} RTSP/1.0`,a=this.cseq++;t.CSeq=a.toString(),t["User-Agent"]="Scrypted",this.wwwAuthenticate&&(t.Authorization=await this.createAuthorizationHeader(e,new d.URL(r))),this.session&&(t.Session=this.session),this.write(s,t,i)}async handleDataPayload(e){if(e[0]!==t.RTSP_FRAME_MAGIC)throw new Error("RTSP Client received invalid frame magic. This may be a bug in your camera firmware. If this error persists, switch your RTSP Parser to FFmpeg or Scrypted (UDP): "+e.toString());const n=e.readUInt8(1),i=e.readUInt16BE(2),r=await(0,g.readLength)(this.client,i),o=this.setupOptions.get(n);o?.onRtp?.(e,r)}async readDataPayload(){const e=await(0,g.readLength)(this.client,4);return this.handleDataPayload(e)}createBadHeader(e){return new Error("RTSP Client received invalid frame magic. This may be a bug in your camera firmware. If this error persists, switch your RTSP Parser to FFmpeg or Scrypted (UDP): "+e.toString())}async readLoopLegacy(){try{for(;;)this.needKeepAlive&&(this.needKeepAlive=!1,this.hasGetParameter?await this.getParameter():await this.options()),await this.readDataPayload()}catch(e){throw this.client.destroy(e),e}}async*handleStream(){for(;;){const e=await(0,g.readLength)(this.client,4);if(e[0]!==t.RTSP_FRAME_MAGIC){if("RTSP"!==e.toString())throw this.createBadHeader(e);this.client.unshift(e);const t=await super.readMessage();await this.readBody(R(t));continue}const n=e.readUInt16BE(2),i=await(0,g.readLength)(this.client,n),r=e.readUInt8(1);yield{channel:r,rtcp:r%2==1,header:e,packet:i}}}async readLoop(){const e=new h.Deferred;let n,i,r;const o=async()=>{this.needKeepAlive&&(this.needKeepAlive=!1,this.hasGetParameter?this.writeGetParameter():this.writeOptions());try{for(;;){if(!n){if(n=this.client.read(4),!n)return;if(n[0]!==t.RTSP_FRAME_MAGIC){if("RTSP"!==n.toString())throw this.createBadHeader(n);this.client.unshift(n),n=void 0,this.client.removeListener("readable",o);const e=await super.readMessage();await this.readBody(R(e));this.client.on("readable",o);continue}i=n.readUInt8(1),r=n.readUInt16BE(2)}const e=this.client.read(r);if(!e)return;const s=n;n=void 0;const a=this.setupOptions.get(i);a?.onRtp?.(s,e)}}catch(t){e.finished||e.reject(t),this.client.destroy()}};o(),this.client.on("readable",o),await Promise.all([(0,u.once)(this.client,"end")])}async readMessage(){for(;;){const e=await(0,g.readLength)(this.client,4);if(e[0]!==t.RTSP_FRAME_MAGIC){if("RTSP"===e.toString()){this.client.unshift(e);return await super.readMessage()}throw this.createBadHeader(e)}await this.handleDataPayload(e)}}async createAuthorizationHeader(e,t){if(!this.wwwAuthenticate)throw new Error("no WWW-Authenticate found");const{BASIC:i}=await Promise.resolve().then(n.bind(n,7284)),{parseHTTPHeadersQuotedKeyValueSet:r}=await Promise.resolve().then(n.bind(n,2238)),o=new d.URL(this.url),s=decodeURIComponent(o.username),a=decodeURIComponent(o.password);if(this.wwwAuthenticate.includes("Basic")){return`Basic ${i.computeHash({username:s,password:a})}`}const u=r(this.wwwAuthenticate,{indexOf:()=>0},w),l=new d.URL(t.toString());l.username="",l.password="";const p=c.default.createHash("md5").update(`${s}:${u.realm}:${a}`).digest("hex"),h=c.default.createHash("md5").update(`${e}:${l}`).digest("hex"),f=c.default.createHash("md5").update(`${p}:${u.nonce}:${h}`).digest("hex"),m={username:s,realm:u.realm,nonce:u.nonce,uri:l.toString(),algorithm:"MD5",response:f};return`Digest ${Object.entries(m).map((([e,t])=>{return`${e}=${t&&(n=t,`"${n.replace(/"/g,'\\"')}"`)}`;var n})).join(", ")}`}async readBody(e){return S(this.client,e)}async request(e,t,n,i,r){await this.writeRequest(e,t,n,i);const o=this.requestTimeout?await(0,m.timeoutPromise)(this.requestTimeout,this.readMessage()):await this.readMessage(),s=o[0],[a,c,u]=s.split(" ",3),l=parseInt(c),p=R(o),d={line:s,code:l,version:a,reason:u};if(200!==l&&!p["www-authenticate"])throw new L(d);const h=k(o)||p["www-authenticate"];if(h){if(r)throw new Error("auth failed");return this.wwwAuthenticate=h,this.request(e,t,n,i,!0)}return{headers:p,body:await this.readBody(p),status:d}}async options(){const e=await this.request("OPTIONS",{}),t=e.headers.public;return t&&(this.hasGetParameter=t.toLowerCase().includes("get_parameter")),e}writeOptions(){return this.writeRequest("OPTIONS")}async getParameter(){return this.request("GET_PARAMETER")}writeGetParameter(){return this.writeRequest("GET_PARAMETER")}async describe(e){const t=await this.request("DESCRIBE",{...e||{},Accept:"application/sdp"});return this.contentBase=t.headers["content-base"]||t.headers["content-location"],this.contentBase&&(this.contentBase=new d.URL(this.contentBase,this.url).toString()),t}async setup(e,t){const n="udp"===e.type?"":"/TCP",i="udp"===e.type?"client_port":"interleaved";let r;if("tcp"===e.type)r=e.port;else{if(!e.dgram){const t=await(0,f.createBindZero)();e.dgram=t.server,this.client.on("close",(()=>(0,f.closeQuiet)(t.server)))}r=e.dgram.address().port,e.dgram.on("message",(t=>e.onRtp(void 0,t)))}t=Object.assign({Transport:`RTP/AVP${n};unicast;${i}=${r}-${r+1}`},t);const o=await this.request("SETUP",t,e.path);let s;if(o.headers.session){const e=N(o.headers.session);let t=parseInt(e.timeout);if(t){let e=setInterval((()=>this.needKeepAlive=!0),1e3*(t-5));this.client.once("close",(()=>clearInterval(e)))}this.session=o.headers.session.split(";")[0]}if(o.headers.transport){const e=o.headers.transport.match(/.*?interleaved=([0-9]+)-([0-9]+)/);if(e){const[t,n,i]=e;n&&i&&(s={begin:parseInt(n),end:parseInt(i)})}}return"tcp"===e.type&&this.setupOptions.set(s?s.begin:r,e),Object.assign({interleaved:s,options:e},o)}async play(e={},t="0.000"){return e.Range=`npt=${t}-`,this.request("PLAY",e)}writePlay(e="0.000"){const t={Range:`npt=${e}-`};return this.writeRequest("PLAY",t)}writeRtpPayload(e,t){return this.client.write(e),this.client.write(Buffer.from(t))}send(e,n){const i=Buffer.alloc(4);return i.writeUInt8(t.RTSP_FRAME_MAGIC,0),i.writeUInt8(n,1),i.writeUInt16BE(e.length,2),this.writeRtpPayload(i,e)}async pause(){return this.request("PAUSE")}async teardown(){try{return await this.request("TEARDOWN")}finally{this.client.destroy()}}writeTeardown(){this.writeRequest("TEARDOWN")}};class F{constructor(e,t,n,i){this.client=e,this.sdp=t,this.udp=n,this.checkRequest=i,this.setupTracks={},this.availableOptions=["DESCRIBE","OPTIONS","PAUSE","PLAY","SETUP","TEARDOWN","ANNOUNCE","RECORD","GET_PARAMETER"],this.session=(0,c.randomBytes)(4).toString("hex"),t&&(t=t.trim()),e instanceof l.default.Socket&&e.setNoDelay(!0)}async handleSetup(e=["play","record","teardown"]){let t=[];for(;;){let n=await(0,g.readLine)(this.client);if(n=n.trim(),n)t.push(n);else{const n=await this.headers(t);if(e.includes(n))return n;t=[]}}}async handlePlayback(){return this.handleSetup()}async handleTeardown(){return this.handleSetup()}async*handleRecord(){for(;;){const e=await(0,g.readLength)(this.client,4);if(e[0]!==t.RTSP_FRAME_MAGIC)throw new Error("RTSP Server expected frame magic but received: "+e.toString());const n=e.readUInt16BE(2),i=await(0,g.readLength)(this.client,n),r=e.readUInt8(1),o=r-r%2,s=Object.values(this.setupTracks).find((e=>e.destination===o));if(!s)throw new Error("RSTP Server received unknown channel: "+r);yield{type:s.codec,rtcp:r%2==1,header:e,packet:i}}}writeRtpPayload(e,t){return this.client.write(e),this.client.write(Buffer.from(t))}send(e,t){const n=Buffer.alloc(4);return n.writeUInt8(36,0),n.writeUInt8(t,1),n.writeUInt16BE(e.length,2),this.writeRtpPayload(n,e)}sendUdp(e,t,n){e.send(n,t,"127.0.0.1")}sendTrack(e,t,n){const i=this.setupTracks[e];return i?"udp"===i.protocol?(this.udp?this.sendUdp(n?i.rtcp:i.rtp,i.destination,t):this.console?.warn("RTSP Server UDP socket not available."),!0):this.send(t,n?i.destination+1:i.destination):(this.console?.warn("RTSP Server track not found:",e),!0)}options(e,t){const n={};n.Public=this.availableOptions.join(", "),this.respond(200,"OK",t,n)}async get_parameter(e,t){this.respond(200,"OK",t,{})}describe(e,t){const n={};n["Content-Base"]=e,n["Content-Type"]="application/sdp",this.respond(200,"OK",t,n,Buffer.from(this.sdp))}setupInterleaved(e,t,n){this.setupTracks[e.control]={control:e.control,protocol:"tcp",destination:t,codec:e.codec}}async setup(e,t){const n={};let i=t.transport;n.Session=this.session;const r=(0,y.parseSdp)(this.sdp).msections.find((t=>e.endsWith(t.control)));if(r){if(i.includes("TCP"))if(this.resolveInterleaved){const[e,t]=this.resolveInterleaved(r);this.setupInterleaved(r,e,t),i=`RTP/AVP/TCP;unicast;interleaved=${e}-${t}`}else{const e=i.match(/.*?interleaved=([0-9]+)-([0-9]+)/);if(e){const t=parseInt(e[1]),n=parseInt(e[2]);this.setupInterleaved(r,t,n)}}else{if(!this.udp)return void this.respond(461,"Unsupported Transport",t,{});const e=i.match(/.*?client_port=([0-9]+)-([0-9]+)/),[n,o,s]=e,[a,c]=await(0,f.createSquentialBindZero)();this.client.on("close",(()=>(0,f.closeQuiet)(a.server))),this.client.on("close",(()=>(0,f.closeQuiet)(c.server))),this.setupTracks[r.control]={control:r.control,protocol:"udp",destination:parseInt(o),codec:r.codec,rtp:a.server,rtcp:c.server},i=i.replace("RTP/AVP/UDP","RTP/AVP").replace("RTP/AVP","RTP/AVP/UDP"),i+=`;server_port=${a.port}-${c.port}`}n.Transport=i,this.respond(200,"OK",t,n)}else this.respond(404,"Not Found",t,n)}play(e,t){const n={},i=Object.values(this.setupTracks).map((t=>`url=${e}/${t.control}`)).join(",");n["RTP-Info"]=i,n.Range="npt=now-",n.Session=this.session,this.respond(200,"OK",t,n)}async announce(e,t){const n=parseInt(t["content-length"]),i=await(0,g.readLength)(this.client,n);this.sdp=i.toString();const r={};r.Session=this.session,this.respond(200,"OK",t,r)}async record(e,t){const n={};n.Session=this.session,this.respond(200,"OK",t,n)}async teardown(e,t){const n={};n.Session=this.session,this.respond(200,"OK",t,n),this.client.destroy()}async headers(e){this.console?.log("request headers",e.join("\n"));let[t,n]=e[0].split(" ",2);t=t.toLowerCase();const i=R(e);if(this.checkRequest){let r;try{r=await this.checkRequest(t,n,i,e)}catch(e){this.console?.error("error checking request",e)}if(!r)throw this.respond(400,"Bad Request",i,{}),this.client.destroy(),new Error("check request failed")}if(this[t]&&this.availableOptions.includes(t.toUpperCase()))return await this[t](n,i),t;this.respond(400,"Bad Request",i,{})}respond(e,t,n,i,r){let o=`RTSP/1.0 ${e} ${t}\r\n`;n.cseq&&(i.CSeq=n.cseq),r&&(i["Content-Length"]=r.length.toString());for(const[e,t]of Object.entries(i))o+=`${e}: ${t}\r\n`;this.console?.log("response headers",o),o+="\r\n",this.client.write(o),r&&(this.client.write(r),this.console?.log("response body",r.toString()))}destroy(){this.client.destroy();for(const e of Object.values(this.setupTracks))(0,f.closeQuiet)(e.rtp),(0,f.closeQuiet)(e.rtcp)}}t.RtspServer=F},394:e=>{function t(e){var t=new Error("Cannot find module '"+e+"'");throw t.code="MODULE_NOT_FOUND",t}t.keys=()=>[],t.resolve=t,t.id=394,e.exports=t},431:function(e,t,n){"use strict";var i,r=this&&this.__createBinding||(Object.create?function(e,t,n,i){void 0===i&&(i=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,i,r)}:function(e,t,n,i){void 0===i&&(i=n),e[i]=t[n]}),o=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),s=this&&this.__importStar||(i=function(e){return i=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},i(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=i(e),s=0;s<n.length;s++)"default"!==n[s]&&r(t,e,n[s]);return o(t,e),t});Object.defineProperty(t,"__esModule",{value:!0});const a=n(7724),c=s(n(2743)),u=n(1414),l=n(2203),p=n(4053),d=n(18),h=n(7545),f=n(9847),m=n(7443);class g extends c.ScryptedDeviceBase{constructor(e,t){super(t),this.camera=e}async turnOff(){this.on=!1,await this.setSiren(!1)}async turnOn(){this.on=!0,await this.setSiren(!0)}async setSiren(e){const t=this.camera.getClient();if(this.camera.storageSettings.values.doorbell)return e?(this.sirenTimeout=setTimeout((async()=>{await this.turnOff()}),4e3),void await t.setSiren(!0,1)):(clearInterval(this.sirenTimeout),void await t.setSiren(!1));await t.setSiren(e)}}class y extends c.ScryptedDeviceBase{constructor(e,t){super(t),this.camera=e}async setBrightness(e){this.brightness=e,await this.setFloodlight(void 0,e)}async turnOff(){this.on=!1,await this.setFloodlight(!1)}async turnOn(){this.on=!0,await this.setFloodlight(!0)}async setFloodlight(e,t){const n=this.camera.getClientWithToken();await n.setWhiteLedState(e,t)}}class v extends c.ScryptedDeviceBase{constructor(e,t){super(t),this.camera=e}async turnOff(){this.on=!1,await this.setPir(!1)}async turnOn(){this.on=!0,await this.setPir(!0)}async setPir(e){const t=this.camera.getClientWithToken();await t.setPirState(e)}}class w extends p.RtspSmartCamera{constructor(e,t){super(e,t),this.onvifIntercom=new f.OnvifIntercom(this),this.storageSettings=new u.StorageSettings(this,{doorbell:{title:"Doorbell",description:"This camera is a Reolink Doorbell.",type:"boolean"},rtmpPort:{subgroup:"Advanced",title:"RTMP Port Override",placeholder:"1935",type:"number"},motionTimeout:{subgroup:"Advanced",title:"Motion Timeout",defaultValue:20,type:"number"},hasObjectDetector:{json:!0,hide:!0},ptz:{subgroup:"Advanced",title:"PTZ Capabilities",choices:["Pan","Tilt","Zoom"],multiple:!0,onPut:async()=>{await this.updateDevice(),this.updatePtzCaps()}},presets:{subgroup:"Advanced",title:"Presets",description:'PTZ Presets in the format "id=name". Where id is the PTZ Preset identifier and name is a friendly name.',multiple:!0,defaultValue:[],combobox:!0,onPut:async(e,t)=>{const n={...this.ptzCapabilities,presets:{}};for(const e of t){const[t,i]=e.split("=");n.presets[t]=i}this.ptzCapabilities=n},mapGet:()=>{const e=this.ptzCapabilities?.presets||{};return Object.entries(e).map((([e,t])=>e+"="+t))}},cachedPresets:{multiple:!0,hide:!0,json:!0,defaultValue:[]},deviceInfo:{json:!0,hide:!0},abilities:{json:!0,hide:!0},useOnvifDetections:{subgroup:"Advanced",title:"Use ONVIF for Object Detection",choices:["Default","Enabled","Disabled"],defaultValue:"Default"},useOnvifTwoWayAudio:{subgroup:"Advanced",title:"Use ONVIF for Two-Way Audio",type:"boolean"}}),this.storageSettings.settings.useOnvifTwoWayAudio.onGet=async()=>({hide:!!this.storageSettings.values.doorbell}),this.storageSettings.settings.ptz.onGet=async()=>({hide:!!this.storageSettings.values.doorbell}),this.storageSettings.settings.presets.onGet=async()=>({choices:this.storageSettings.values.cachedPresets.map((e=>e.id+"="+e.name))}),this.updateDeviceInfo(),(async()=>{this.updatePtzCaps();try{await this.getPresets()}catch(e){this.console.log("Fail fetching presets",e)}const e=this.getClient(),t=await e.getDeviceInfo();this.console.log("deviceInfo",JSON.stringify(t)),this.storageSettings.values.deviceInfo=t,await this.updateAbilities(),await this.updateDevice(),await this.reportDevices(),await this.checkNetData(),this.startDevicesStatesPolling()})().catch((e=>{this.console.log("device refresh failed",e)}))}async pollDeviceStates(){try{const e=this.getClient();try{if(this.hasFloodlight()&&this.floodlight){const{enabled:t}=await e.getWhiteLedState();t!==this.floodlight.on&&(this.floodlight.on=t)}}catch{}try{if(this.hasPirSensor()&&this.pirSensor){const{enabled:t}=await e.getPirState();t!==this.pirSensor.on&&(this.pirSensor.on=t)}}catch{}}catch(e){this.console.error("Error in pollDeviceStates",e)}}async startDevicesStatesPolling(){if(!this.hasBattery()&&(this.hasFloodlight()||this.hasSiren()||this.hasPirSensor()))for(;;)await this.pollDeviceStates(),await(0,a.sleep)(5e3)}async getVideoTextOverlays(){const e=this.getClient(),t=await e.getOsd();return{osdChannel:{text:t.value.Osd.osdChannel.enable?t.value.Osd.osdChannel.name:void 0},osdTime:{text:!!t.value.Osd.osdTime.enable,readonly:!0}}}async setVideoTextOverlay(e,t){const n=this.getClient(),i=await n.getOsd();if("osdChannel"===e){const e=i.value.Osd.osdChannel;e.enable=t.text?1:0,e.name="string"==typeof t.text&&t.text?t.text:e.name||"Camera"}else{if("osdTime"!==e)throw new Error("unknown overlay: "+e);i.value.Osd.osdTime.enable=t.text?1:0}await n.setOsd(i)}updatePtzCaps(){const{ptz:e}=this.storageSettings.values;this.ptzCapabilities={...this.ptzCapabilities,pan:e?.includes("Pan"),tilt:e?.includes("Tilt"),zoom:e?.includes("Zoom")}}async getPresets(){const e=this.getClient(),t=await e.getPtzPresets();this.console.log(`Presets: ${JSON.stringify(t)}`),this.storageSettings.values.cachedPresets=t}async updateAbilities(){const e=this.getClient(),t=this.getClientWithToken();let n;try{n=await e.getAbility()}catch(e){n=await t.getAbility()}try{const{isWifi:e}=await t.getLocalLink();this.isWifi=e}catch{}this.storageSettings.values.abilities=n,this.console.log("getAbility",JSON.stringify(n))}supportsOnvifDetections(){return["CX410W","Reolink Video Doorbell WiFi","CX410","CX810","Reolink Video Doorbell PoE"].includes(this.storageSettings.values.deviceInfo?.model)}async getDetectionInput(e,t){}async ptzCommand(e){this.getClient().ptz(e)}async getObjectTypes(){try{const e=this.storageSettings.values.hasObjectDetector?.value,t=[];for(const n of Object.keys(e)){if("channel"===n)continue;const{alarm_state:i,support:r}=e[n];r&&t.push(n)}return{classes:t}}catch(e){return{classes:[]}}}async startIntercom(e){if(!this.onvifIntercom.url){const e=await this.getOnvifClient(),t=await e.getStreamUrl();this.onvifIntercom.url=t}return this.onvifIntercom.startIntercom(e)}stopIntercom(){return this.onvifIntercom.stopIntercom()}hasSiren(){const e=this.getRtspChannel(),t=this.storageSettings.values.abilities?.value?.Ability?.supportAudioAlarm,n=this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[e]?.supportAudioAlarm;return t&&0!==t?.ver||n&&0!==n?.ver}hasFloodlight(){const e=this.getRtspChannel(),t=this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[e];if(t){const e=t.floodLight?.ver??0,n=t.supportFLswitch?.ver??0,i=t.supportFLBrightness?.ver??0;return e>0||n>0||i>0}return!1}hasBattery(){return(this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[this.getRtspChannel()]?.battery?.ver??0)>0}hasPirEvents(){return(this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[this.getRtspChannel()]?.mdWithPir?.ver??0)>0}hasPirSensor(){return(this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[this.getRtspChannel()]?.mdWithPir?.ver??0)>0}hasRtsp(){const e=this.storageSettings.values.abilities?.value?.Ability?.supportRtspEnable;return e&&0!==e?.ver}hasRtmp(){const e=this.storageSettings.values.abilities?.value?.Ability?.supportRtmpEnable;return e&&0!==e?.ver}hasOnvif(){const e=this.storageSettings.values.abilities?.value?.Ability?.supportOnvifEnable;return e&&0!==e?.ver}hasHttps(){const e=this.storageSettings.values.abilities?.value?.Ability?.supportHttpsEnable;return e&&0!==e?.ver}async updateDevice(){const e=this.provider.getInterfaces();let t=c.ScryptedDeviceType.Camera,n="Reolink Camera";this.storageSettings.values.doorbell&&(e.push(c.ScryptedInterface.BinarySensor),t=c.ScryptedDeviceType.Doorbell,n="Reolink Doorbell"),(this.storageSettings.values.doorbell||this.storageSettings.values.useOnvifTwoWayAudio)&&e.push(c.ScryptedInterface.Intercom),this.storageSettings.values.ptz?.length&&e.push(c.ScryptedInterface.PanTiltZoom),this.storageSettings.values.hasObjectDetector&&e.push(c.ScryptedInterface.ObjectDetector),(this.hasSiren()||this.hasFloodlight()||this.hasPirSensor())&&e.push(c.ScryptedInterface.DeviceProvider),this.hasBattery()&&(e.push(c.ScryptedInterface.Battery,c.ScryptedInterface.Sleep),this.startBatteryCheckInterval()),await this.provider.updateDevice(this.nativeId,this.name??n,e,t)}startBatteryCheckInterval(){this.batteryTimeout&&clearInterval(this.batteryTimeout),this.batteryTimeout=setInterval((async()=>{const e=this.getClientWithToken();try{const{batteryPercent:t,sleeping:n}=await e.getBatteryInfo();this.batteryLevel=t,n!==this.sleeping&&(this.sleeping=n,n||await this.pollDeviceStates()),t!==this.batteryLevel&&(this.batteryLevel=t)}catch(e){this.console.log("Error in getting battery info",e)}}),1e4)}async reboot(){const e=this.getClient();await e.reboot()}updateDeviceInfo(){const e=this.storage.getItem("ip");if(!e)return;const t=this.info||{};t.ip=e,t.serialNumber=this.storageSettings.values.deviceInfo?.serial,t.firmware=this.storageSettings.values.deviceInfo?.firmVer,t.version=this.storageSettings.values.deviceInfo?.hardVer,t.model=this.storageSettings.values.deviceInfo?.model,t.manufacturer="Reolink",t.managementUrl=`http://${e}`,this.info=t}getClient(){return this.client||(this.client=new m.ReolinkCameraClient(this.getHttpAddress(),this.getUsername(),this.getPassword(),this.getRtspChannel(),this.console)),this.client}getClientWithToken(){return this.clientWithToken||(this.clientWithToken=new m.ReolinkCameraClient(this.getHttpAddress(),this.getUsername(),this.getPassword(),this.getRtspChannel(),this.console,!0)),this.clientWithToken}async getOnvifClient(){return this.onvifClient||(this.onvifClient=await this.createOnvifClient()),this.onvifClient}createOnvifClient(){return(0,d.connectCameraAPI)(this.getHttpAddress(),this.getUsername(),this.getPassword(),this.console,this.storageSettings.values.doorbell?this.storage.getItem("onvifDoorbellEvent"):void 0)}async listenEvents(){let e=!1;const t=this.getClient(),n=await t.getDeviceInfo();if("Default"===this.storageSettings.values.useOnvifDetections&&(this.supportsOnvifDetections()||this.storageSettings.values.doorbell)||"Enabled"===this.storageSettings.values.useOnvifDetections){const t=await(0,h.listenEvents)(this,await this.createOnvifClient(),1e3*this.storageSettings.values.motionTimeout);return t.on("onvifEvent",((e,n)=>{let i;if(e.includes("PeopleDetect")?i="people":e.includes("FaceDetect")?i="face":e.includes("VehicleDetect")?i="vehicle":e.includes("DogCatDetect")?i="dog_cat":e.includes("Package")&&(i="package"),i&&n){t.emit("event",d.OnvifEvent.MotionStart);const e={timestamp:Date.now(),detections:[{className:i,score:1}],sourceId:this.pluginId};c.default.deviceManager.onDeviceEvent(this.nativeId,c.ScryptedInterface.ObjectDetector,e)}else t.emit("event",d.OnvifEvent.MotionStop)})),t.on("close",(()=>e=!0)),t.on("error",(()=>e=!0)),t}const i=new l.EventEmitter,r={on:function(e,t){i.on(e,t)},destroy:function(){e=!0},emit:function(e,...t){return i.emit(e,...t)}},o=()=>{this.motionDetected=!0,clearTimeout(this.motionTimeout),this.motionTimeout=setTimeout((()=>this.motionDetected=!1),1e3*this.storageSettings.values.motionTimeout)};return(async()=>{for(;!e;){try{if(this.hasPirEvents()){const{value:e,data:n}=await t.getEvents();e?.other?.alarm_state&&o(),r.emit("data",JSON.stringify(n))}else{const{value:e,data:n}=await t.getMotionState();e&&o(),r.emit("data",JSON.stringify(n))}}catch(e){r.emit("error",e)}await(0,a.sleep)(1e3)}})(),(async(i,r)=>{let o=!1,s=!1;for(;!e;){try{const e=this.hasPirEvents()?await t.getEvents():await t.getAiState();i.emit("data",JSON.stringify(e.data));const n=[];for(const t of Object.keys(e.value)){if("channel"===t)continue;const{support:i}=e.value[t];i&&n.push(t)}if(!n.length)return;s||(s=!0,this.storageSettings.values.hasObjectDetector=e),o=!0;const a={timestamp:Date.now(),detections:[],sourceId:this.pluginId};for(const t of n){const{alarm_state:n}=e.value[t];n&&a.detections.push({className:t,score:1})}a.detections.length&&(r(),c.default.deviceManager.onDeviceEvent(this.nativeId,c.ScryptedInterface.ObjectDetector,a))}catch(e){if(!o&&!(0,m.isDeviceNvr)(n))return;i.emit("error",e)}await(0,a.sleep)(1e3)}})(r,o),r}async takeSmartCameraPicture(e){return this.createMediaObject(await this.getClient().jpegSnapshot(e?.timeout),"image/jpeg")}async getUrlSettings(){return[{key:"rtspChannel",title:"Channel Number Override",subgroup:"Advanced",description:"The channel number to use for snapshots and video. E.g., 0, 1, 2, etc.",placeholder:"0",type:"number",value:this.getRtspChannel()},...await super.getUrlSettings()]}getRtspChannel(){return parseInt(this.storage.getItem("rtspChannel"))||0}createRtspMediaStreamOptions(e,t){const n=(0,p.createRtspMediaStreamOptions)(e,t);return n.tool="scrypted",n}addRtspCredentials(e){const t=new URL(e);if("rtmp:"!==t.protocol)t.username=this.storage.getItem("username"),t.password=this.storage.getItem("password")||"";else{const e=t.searchParams;for(const[t,n]of Object.entries(this.client.parameters))e.set(t,n)}return t.toString()}async createVideoStream(e){return await this.client.login(),super.createVideoStream(e)}async getConstructedVideoStreamOptions(){let e,t;try{const t=this.getClient();e=await t.getDeviceInfo()}catch(e){this.console.error("Unable to gather device information.",e)}try{const e=this.getClient();t=await e.getEncoderConfiguration()}catch(e){this.console.error("Codec query failed. Falling back to known defaults.",e)}const n=this.getRtspChannel(),i=(n+1).toString().padStart(2,"0"),r=[{name:"",id:"main.bcs",container:"rtmp",video:{width:2560,height:1920},url:""},{name:"",id:"ext.bcs",container:"rtmp",video:{width:896,height:672},url:""},{name:"",id:"sub.bcs",container:"rtmp",video:{width:640,height:480},url:""},{name:"",id:`h264Preview_${i}_main`,container:"rtsp",video:{codec:"h264",width:2560,height:1920},url:""},{name:"",id:`h264Preview_${i}_sub`,container:"rtsp",video:{codec:"h264",width:640,height:480},url:""}],o=this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[n]?.live?.ver,[s,a,c,u,l]=r;r.splice(0,r.length);const p=this.storageSettings.values.abilities?.value?.Ability?.abilityChn?.[n]?.mainEncType?.ver;(0,m.isDeviceHomeHub)(e)?r.push(u,l):2===o?1===p?r.push(c,u,l):r.push(s,c,u,l):1===p?r.push(a,c,u,l):r.push(s,a,c,u,l),e?.model&&["Reolink TrackMix PoE","Reolink TrackMix WiFi","RLC-81MA","Trackmix Series W760"].includes(e?.model)&&(r.push({name:"",id:"autotrack.bcs",container:"rtmp",video:{width:896,height:512},url:""}),0===n&&r.push({name:"",id:"h264Preview_02_main",container:"rtsp",video:{codec:"h264",width:3840,height:2160},url:""},{name:"",id:"h264Preview_02_sub",container:"rtsp",video:{codec:"h264",width:640,height:480},url:""}));for(const e of r){var d;if("rtmp"===e.container){const t=(d=new URL(`rtmp://${this.getRtmpAddress()}/bcs/channel${n}_${e.id}`)).searchParams;t.set("channel",n.toString()),t.set("stream","0"),e.url=d.toString(),e.name=`RTMP ${e.id}`}else"rtsp"===e.container&&(d=new URL(`rtsp://${this.getRtspAddress()}/${e.id}`),e.url=d.toString(),e.name=`RTSP ${e.id}`)}if(t){const{mainStream:e}=t;if(e?.width&&e?.height)for(const t of r)"main.bcs"!==t.id&&t.id!==`h264Preview_${i}_main`||(t.video.width=e.width,t.video.height=e.height),"h265"!==e.vType&&"hevc"!==e.vType||t.id===`h264Preview_${i}_main`&&(this.console.warn("Detected h265. Change the camera configuration to use 2k mode to force h264. https://docs.scrypted.app/camera-preparation.html#h-264-video-codec"),t.video.codec="h265",t.id=`h265Preview_${i}_main`,t.name=`RTSP ${t.id}`,t.url=`rtsp://${this.getRtspAddress()}/${t.id}`)}return r}async putSetting(e,t){this.client=void 0,this.storageSettings.keys[e]?await this.storageSettings.putSetting(e,t):await super.putSetting(e,t),this.updateDevice(),this.updateDeviceInfo()}showRtspUrlOverride(){return!1}async getRtspPortOverrideSettings(){return[...await super.getRtspPortOverrideSettings()]}async getOtherSettings(){const e=await super.getOtherSettings();return[...await this.storageSettings.getSettings(),...e]}getRtmpAddress(){return`${this.getIPAddress()}:${this.storage.getItem("rtmpPort")||1935}`}async reportDevices(){const e=this.hasSiren(),t=this.hasFloodlight(),n=this.hasPirSensor(),i=[];if(e){const e=`${this.nativeId}-siren`,t={providerNativeId:this.nativeId,name:`${this.name} Siren`,nativeId:e,info:{...this.info},interfaces:[c.ScryptedInterface.OnOff],type:c.ScryptedDeviceType.Siren};i.push(t)}if(t){const e=`${this.nativeId}-floodlight`,t={providerNativeId:this.nativeId,name:`${this.name} Floodlight`,nativeId:e,info:{...this.info},interfaces:[c.ScryptedInterface.OnOff],type:c.ScryptedDeviceType.Light};i.push(t)}if(n){const e=`${this.nativeId}-pir`,t={providerNativeId:this.nativeId,name:`${this.name} PIR sensor`,nativeId:e,info:{...this.info},interfaces:[c.ScryptedInterface.OnOff],type:c.ScryptedDeviceType.Switch};i.push(t)}c.default.deviceManager.onDevicesChanged({providerNativeId:this.nativeId,devices:i})}async checkNetData(){try{const e=this.getClientWithToken(),{netData:t}=await e.getNetData();this.console.log("netData",JSON.stringify(t));const n=this.storageSettings.values.deviceInfo,i=(0,m.isDeviceHomeHub)(n),r=!!this.hasHttps()&&1===t.httpsEnable,o=!!this.hasRtmp()&&(!i&&0===t.rtmpEnable),s=!!this.hasRtmp()&&(i&&1===t.rtmpEnable),a=!!this.hasRtsp()&&0===t.rtspEnable,c=!!this.hasOnvif()&&0===t.onvifEnable;if(this.console.log(`NetData checks: shouldDisableHttps: ${r}, shouldEnableRtmp: ${o}, shouldEnableRtsp: ${a}, shouldEnableOnvif: ${c}, shouldDisableRtmp: ${s}`),r||o||a||c||s){const n={...t};r&&(n.httpsEnable=0),o&&(n.rtmpEnable=1),s&&(n.rtmpEnable=0),a&&(n.rtspEnable=1),c&&(n.onvifEnable=1),this.console.log(`Fixing netdata settings: ${JSON.stringify(n)}`),await e.setNetData(n)}}catch(e){this.console.error("Error in pollDeviceStates",e)}}async getDevice(e){return e.endsWith("-siren")?(this.siren||=new g(this,e),this.siren):e.endsWith("-floodlight")?(this.floodlight||=new y(this,e),this.floodlight):e.endsWith("-pir")?(this.pirSensor||=new v(this,e),this.pirSensor):void 0}async releaseDevice(e,t){t.endsWith("-siren")?delete this.siren:t.endsWith("-floodlight")?delete this.floodlight:t.endsWith("-pir")&&delete this.pirSensor}}class b extends p.RtspProvider{getScryptedDeviceCreator(){return"Reolink Camera"}getAdditionalInterfaces(){return[c.ScryptedInterface.Reboot,c.ScryptedInterface.VideoCameraConfiguration,c.ScryptedInterface.Camera,c.ScryptedInterface.AudioSensor,c.ScryptedInterface.MotionSensor,c.ScryptedInterface.VideoTextOverlays]}async createDevice(e,t){const n=`${e.ip}:${e.httpPort||80}`;const i="true"===e.skipValidate?.toString(),r=e.username?.toString(),o=e.password?.toString();let s,a,c,u=!1,l="Reolink Camera";const p=parseInt(e.rtspChannel?.toString())||0;if(!i){const e=new m.ReolinkCameraClient(n,r,o,p,this.console),t=new m.ReolinkCameraClient(n,r,o,p,this.console,!0);try{await e.jpegSnapshot()}catch(e){throw this.console.error("Error adding Reolink camera",e),e}try{s=await e.getDeviceInfo(),u="BELL"===s.type,l=s.name??"Reolink Camera",a=await e.getAiState();try{c=await e.getAbility()}catch(e){c=await t.getAbility()}}catch(e){this.console.error("Reolink camera does not support AI events",e)}}e.n