WME DOT Cameras

Overlay DOT Cameras on the WME Map Object

  1. // ==UserScript==
  2. // @name WME DOT Cameras
  3. // @namespace https://greasyfork.org/en/users/668704-phuz
  4. // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
  5. // @version 1.69
  6. // @description Overlay DOT Cameras on the WME Map Object
  7. // @author phuz, doctorblah
  8. // @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
  9. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
  10. // @grant GM_xmlhttpRequest
  11. // @grant GM_info
  12. // @grant GM_fetch
  13. // @grant GM_addStyle
  14. // @require https://cdnjs.cloudflare.com/ajax/libs/hls.js/1.1.2-0.canary.8064/hls.js
  15. // @require https://unpkg.com/video.js/dist/video.js
  16. // @require https://unpkg.com/@videojs/http-streaming/dist/videojs-http-streaming.js
  17. // @require https://cdnjs.cloudflare.com/ajax/libs/x2js/1.2.0/xml2json.min.js
  18. // @connect 72.167.49.86
  19. // @connect jsdelivr.net
  20. // @connect 511pa.com
  21. // @connect deldot.gov
  22. // @connect 511ny.org
  23. // @connect 511nj.org
  24. // @connect maryland.gov
  25. // @connect 511virginia.org
  26. // @connect newengland511.org
  27. // @connect algotraffic.com
  28. // @connect nvroads.com
  29. // @connect tn.gov
  30. // @connect 511ga.org
  31. // @connect iteriscdn.com
  32. // @connect skyvdn.com
  33. // @connect idrivearkansas.com
  34. // @connect akamaihd.net
  35. // @connect goakamai.org
  36. // @connect trafficwise.org
  37. // @connect ga.gov
  38. // @connect google.com
  39. // @connect fl511.com
  40. // @connect 511ia.org
  41. // @connect idaho.gov
  42. // @connect arcgis.com
  43. // @connect kandrive.org
  44. // @connect mass511.com
  45. // @connect mi.us
  46. // @connect 511mn.org
  47. // @connect modot.org
  48. // @connect mt.gov
  49. // @connect azureedge.net
  50. // @connect nebraska.gov
  51. // @connect nmroads.com
  52. // @connect ohgo.com
  53. // @connect tripcheck.com
  54. // @connect ri.gov
  55. // @connect utah.gov
  56. // @connect ca.gov
  57. // @connect txdot.gov
  58. // @connect modttraffic.om
  59. // @connect nd.gov
  60. // @connect cttravelsmart.org
  61. // @connect vaisala.com
  62. // @connect skyvdn.com
  63. // @connect cotrip.org
  64. // @connect austintexas.gov
  65. // @connect wyoroad.info
  66. // @connect ncdot.gov
  67. // @connect carsprogram.org
  68. // @connect ksdot.org
  69. // @connect iteris-atis.com
  70. // @connect quebec511.info
  71. // @connect transports.gouv.qc.ca
  72. // @connect ville.montreal.qc.ca
  73. // @connect txdot.gov
  74. // @connect arcadis-ivds.com
  75. /* global OpenLayers */
  76. /* global W */
  77. /* global WazeWrap */
  78. /* global $ */
  79. /* global I18n */
  80. /* global _ */
  81. /* global MutationObserver */
  82. /* global localStorage */
  83.  
  84. // ==/UserScript==
  85.  
  86. let ALLayer, AKLayer, AZLayer, ARLayer, CALayer, COLayer, CTLayer, DELayer, DCLayer, FLLayer, GALayer, HILayer, IDLayer, ILLayer, INLayer, IALayer, KSLayer, KYLayer, LALayer, MELayer, MDLayer, MALayer, MILayer, MNLayer, MSLayer, MOLayer, MTLayer, NELayer, NVLayer, NHLayer, NJLayer, NMLayer, NYLayer, NWLayer, NCLayer, NDLayer, OHLayer, OKLayer, ORLayer, PALayer, QCLayer, RILayer, SCLayer, SDLayer, TNLayer, TXLayer, UTLayer, VTLayer, VALayer, WALayer, WILayer, WVLayer, WYLayer;
  87. let ALFeed = [], AKFeed = [], AZFeed = [], ARFeed = [], CAFeed = [], COFeed = [], CTFeed = [], DEFeed = [], DCFeed = [], FLFeed = [], GAFeed = [], HIFeed = [], IDFeed = [], ILFeed = [], INFeed = [], IAFeed = [], KSFeed = [], KYFeed = [], LAFeed = [], MEFeed = [], MDFeed = [], MAFeed = [], MIFeed = [], MNFeed = [], MSFeed = [], MOFeed = [], MTFeed = [], NEFeed = [], NVFeed = [], NHFeed = [], NJFeed = [], NMFeed = [], NYFeed = [], NWFeed = [], NCFeed = [], NDFeed = [], OHFeed = [], OKFeed = [], ORFeed = [], PAFeed = [], QCFeed = [], RIFeed = [], SCFeed = [], SDFeed = [], TNFeed = [], TXFeed = [], UTFeed = [], VTFeed = [], VAFeed = [], WAFeed = [], WIFeed = [], WVFeed = [], WYFeed;
  88. var localsettings = {}, settings, video, player, hls, staticUpdateID, newZIndex;
  89. var state, stateLength, settingID, cameraKeys = [];
  90. var paToken = "";
  91. let mapBounds;
  92. let showUpdate = false;
  93. const updateMessage = "► Fix for WME update";
  94. const x2js = new X2JS();
  95. const camIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAAGXcA1uAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpBRDNGNTkwRTYzQThFMzExQTc4MDhDNjAwODdEMzdEQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2OUI0RUEyN0IwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2OUI0RUEyNkIwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZGOEJBMzExNkZCMEUzMTFCOEY5QTU3QUQxM0M2MjI5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkFEM0Y1OTBFNjNBOEUzMTFBNzgwOEM2MDA4N0QzN0RBIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+TV0cjwAABbhJREFUeNpiYIAAXiZGCIMPiP//f8DwnwnI+PT/HZD8y8AAEEBQVQzTwOSfuwz/u6qAyh4y/Gf8f4/hPwMnUJSZgQEggMCyzpZAmbsILMTHcAokPhPEWT8dqJoBgvetAtMMDBIiDCf/P4bqeMXwf+t8BiOAAGJAAqVA7A1iPH/+goFBT4OB8f9LJDueAzFQgOHGLoTZYEGgpJgww0+G/68ZQArAEsryEHpRN5BuK4FIcHMhjJORVTvBYG3MwPD2CkKwKAVI/3nBABBAYOcY6zKAjGSQEmP4cGkXxMlgK4BeaCll+B/lzzDh/yegmr8vIO4HGv/l/0eG/w4WDP9fnUM4Dhl/uMzwf/6CFQ4g9RUgE3ctRvgGGSvJMfw/tw3i7sY8hv8sQMGrQE8yuFoBZe8CeRwMDIKaDAyWRgwM2xYD+exA/AuIvwAV3kaE6sSPQCuBHv2vqczwf0YL0MR7SE4CsgsTGP5///aSCZQSGDRVGPJfv2dgNDNkcP30heHbB6BpyzYyMCRVMjCwqDIcOX+LgTEtioGRhfn/P4AAbJTfK0NhGMe/Z+ecpVkrScnIlCiWkoulpFyhxgXKXCGK3XGBG/4BJcoNN665tqsxo6XshiKtyQybn82vMZPF63nPOXKYi+fieU7P8z59P9/n6NlBVNrRRDFPMUlRIGhmM0gWzk5NSCFMuDE2MqAaUJGUhDgOgNmKkXmLwMRudA11diynI9lSKhEHG+oBu9q1mHkDf9AWWkM0dgHEb4H+PqqkKD51uxpJuSoDHpIfAowyohyUveJH+9pqUjigav/9UnIfzO/frkRvBxUuwcpK/gc3PkzfzynuwRoanYuStZDKaeAkwA8QEPJ/CYfpBUCmqxp1E7uXJ6u0tUNVQbvIR+DIBzgHgQMvrZ5LZWIiSuowh6N+nQ9ZYgnNcLTzdRBsz5Ot1socWCr1KipYulrJVDIQjqjwgqsESvcPQB5QWmP2nsWem5X80IeizhaadPfHQwTxnXJTDk5ZQgeOOCC0ScY0wtPdRrc4AzY7BVZuQ8bVDhcXJLyhNnwJUFj5hTQVhmH8mQ7H5nYYkRxJw8hqBWYsLIr+gisKYobdjKguClOKLiQvgrrwqogiIr1wECHdRCCjIopNiCKZIGkthysrrWSklg36M6O5fT3fzmk7C8kDL4zt2/neP8/ze01/b6XuceWsVmAJJR56gurObjSn0/DWrEY152SmIyFBNk1sxZhBZAQTyVmEDjeiy9eAQdm4FK1gLlHg8Y3CYlXzZW12A1+GYd1Yi1u1LogXQSYgmxdnjM8jsTFNZvLMxADE3h0QS8vxNNqLJWKa2ZMXBRXwaaNmL/XdoUct+hhtjF+MFBZ+zJq5Gw6ywoRyI/xs/JjJtCj38+XWo3rGdM6pI3nlqYshmmiGx7fJpLE8rAqGZQy+49o5CNeauoeplJZZPbWfztqSWurvmV/ixrCXQjRSFQE/xI8R/dK44VJae99OorWt/Xh2tZxp0Q+903zynX/q6YLwevgy28IXyiBYxCY3cXYeIvGGRL0Isc697Z5k0NRMQj8Grd92zuDALuAuIRm8CVSohe1uYZ+T74FwADjdBFBh6GgH+mm3ZuLDSb9Ocg9YLNYZOeSyUitevupFeWWVTlzjQ0dNfQJW1fOybulPWlmyZ85wpshQC43/m+9YsR2ZTn9wg5z955+z2FO3H0PRIIqcHHzgPpAgNukwOJzAwCB3NiFQxsyyjJ37J4lMXklpfnaRyidaO3xe7+6h3JmVy2CjkcInD3EO3/T1xsFn3mobX0z+RzkfNAxcpXrIjo+RkFKp0VLkk1hfwwqJr69RODxbcH05gem/wIEN62TV13XuMxNIvqYYqCT6R6x14UHsEarkwhBxJbtnC4wmS9fXDuT2stFkxIDsp4tfbZU5MCr0jnMbIMLoKy7Gc8WunU3rxHMoCmKxUaiqij/5alOWhMPoGAAAAABJRU5ErkJggg==';
  96. const camRed = 'data:image/gif;base64,R0lGODlhGAAYAOYAAAsKABAOAA4MAHI0DmsxDWItDEkiCWcwDVcoC04kCkghCUYgCXw5EF0rDFIlCjcYB4M7ET0bCI5AE4c9EqNFFp5EFZtEFahHF6pIGK1HGK9IGblKG7hIG7NHGiUPBsBJHcJJHsJKHiUOBshIH8ZIH8ZJH81HIcxHIctHIc5FIs5GItFDI8Y/IdNCJNJDJM1AI8xAI8lAIsc/IsM/IcI+Ib48IL49IL08ILs6ILs7IM9BJLc5INQ/Jc4/JLk5ILc4ILY4ILU2ILU3ILM1INU+JrQ0ILM0INY8J7IyILI0ILExINY7J9c5KNY5KNc2KRIEA9c1Kdc0KtcxKxEDA9cuK9csLNctLNcuLAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAFkALAAAAAAYABgAAAfZgFmCg4SFhoeGQTc1P4iOOUxVkpNQNI6ETZOak1KXWZugkzuIoaVVSIZOVSsDJVamk4U5khRYWA8WLbAyhKpVCLa2Uw0bUaWEkkRTwcweEyagSoJCkisLy8zBUwoYR5MdgjWaJxAi2cxPByFVJII2oCnMUwbYUxouVSOCP6A8EcIVqvC4gODDJA6DQjkJkICBqSKDpICiIoAILEI0JgJYYqpHIUkoQIxQkWEKFFOGjFSRQKCBgwIgTOE45OMKrEksHCW5WSWHpywxSun4SWjIDBgvWAAhytRQIAA7';
  97. const staticIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABDBJREFUeNrEV21sU1UYfu7t7W67tmPrWOYmyYCVTFEhqOlYxBA0sh8CMTgI/sAYRI2gQaMJ/CP+IDFRI/xAA/xSxC8+YhRENNmCQWUThs648LFiR8w2WNttXfdx14/j+561w2W92rq2nmTJes4953nOeZ/zvOdVhBBNAN6MxeK1Z87+hou//oHem4NQFAW5bISDqspSPLB0ARpX3gdNs/ioe5dCA9ev+HoX7H7rBNoudSEyYiAajSEfzWrV4HTo8N7vwRuvrUedp6pbGRufEE+9uB/nL1yjgVo0Pe5FxdySvBDoD4Rx7FQbbdSH+mUefPL+duDLb9pFzYOviPVb9opAcFjkuwVCw+LJrfsk5henLwj1fDsd++g4mtZ4Ue52It+tvMyJDYTFmK3tPqihwQhIgAUBT7WyUgfihBkaGoHKame9JxKiYARSWAQO7b8sMEG3RPydL/1vsSh8tbJeK2sCJ7+7hOOnfoaVwZJewXc8EU/g6Y0rsLLh7twRiIyMY++hM5hTYsf2Zx6Dz9+H3W+fQCAYhmaxIHUIzCMajeOa/yY+3r8N86rdsyMQJYG0nOtE8w+dOHL8R7icNoTDY/jl924MhUfpt33GHLsN6OkbwM49n+LRh++Z6o/TydQtrMKK5XUy5hkR+LMnhF17PsMt2mnZHIcUzcEjLdDJyew2q4y/YURJC3G5+yLqLyqaHGOTOfvT5dt6mYhi6eIafPTeNlSmMbi0BHhSglB45xxfBnE5bMkdCRqP4d675sGzsJJiL3C5qwdXfX3QdQ16kVX+TZ0mCZbXMrP3tAT4aqrqzOPi42Sl73iuEZueaEBFuUv2c/L68Og5fPD595KwqqrT5vFaZslNyyabxYjA85tX4eVnV08b4yy386U1GKewHCYiuq4i02SqZkqAd8873rhuuek3G9Z6J10ukcj4FmRMgONY4rLjzjvKTL/xzK+U6VYIkXsCHEPDiMEggZq1AfL2yZuh5J6AhYTVHxhCM/mDWeOxYCiSVsCzJsCLGrS7feSMV6/3zRjv6LyBA4ebKVSJtIaTk1ygk9n4um9hy6sHsWldAx7yLpKpnI3n6Mk2mV5t9E0WEkhPgBcwExKTCAQjePfQabxz4Oup8FitFumU6ab9EyHN9LjJ7cLDYzLp/Ht+j8v8YeaqLNysjKiartqOrY3w3+iHZs0+x09LbKSbxYuq5VMsYwKOYh0vbH6kIK8jFf9zU1Niy+buzho0icXuqrpLnbBQhgsNRApGYGBwRGK66a2hepfVwllsk++8YAFIMAZ7BmPWUyWmjI4asjRrpbqwnsg0ra3HXLcrL+BUFeHYV62Edbs04+LUf6Wrt4Yfm22ySjLkszvXimCl8dPNWZwsTl9PFqep8pyyWO23LR242OFHb/9gVn6eaTqvqqDyfMl8rF61hMhMlud/CTAAgS0zvPJ72lwAAAAASUVORK5CYII=';
  98. const warning = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA/ppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ1dWlkOjVEMjA4OTI0OTNCRkRCMTE5MTRBODU5MEQzMTUwOEM4IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjk4MDFDMjUwNzIzRDExRTNBQTczRjkyOTZEQ0IyOTY0IiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjk4MDFDMjRGNzIzRDExRTNBQTczRjkyOTZEQ0IyOTY0IiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIElsbHVzdHJhdG9yIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ1dWlkOmFiMzczNzVkLWIwYTYtNDRjNC04OTE4LWU4M2ZiOTRhOGY4NSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpjMjUyYWZlMC1mMjU0LWY5NDMtOGZiZi0wMTc3Mzc1ZWEzYzYiLz4gPGRjOnRpdGxlPiA8cmRmOkFsdD4gPHJkZjpsaSB4bWw6bGFuZz0ieC1kZWZhdWx0Ij5JbmNpZGVudHNfb3V0bGluZWQ8L3JkZjpsaT4gPC9yZGY6QWx0PiA8L2RjOnRpdGxlPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pmcc3z4AAASdSURBVHja7FdLaFxVGP7OPfc1M5lMJ5M0Gk0nNdE+sogPLNG2KNaFUksqlkAjSGtcCBJUWgouhErAUOhCwb2uXJQupCtF0I102SrEUsFNkRaxJJ3MTGbu+/j/J2lnKp04HdNkY+AnZ875/u9853/ce65QSmEz/wxs8t//AjZdgDkytL1j5whIaRKgvuERCIH9UDjHpsedRqATJwE8Yimcn5LuVv79deztEQJPU0Nf35AILCZq7lXX3jqds8DGY5574Cmgk6OS4PCoJaamcvSjO9HGY57jtQcqwFPot1V85lhByPHptzBw7jttz9H4eK8hnSQ+4xPmfjhlz5YtbQHprChH6vRrTuXQqddfgP3+HGSuANnVDYw9ix3XL+G3X68UfgkduFJ8L9Y7AvUYL+7MipMndig4eQdKNOqXx07exomdCoxh7LqmIFRwbYHP3t1uYHevgXq9CgRNre/X9ByvMYax7LN+EVA4/XKfMTbRJ3GzYiKs+lCh31gOA4Tlul5jDGPZZ10ERAp7C7aYmX7YgvIl6p4Fv+IjCcJGfZAAvxroNcYwln3Y978KkLVEfXK0z0yPmAbKNYEglAjKAZ06bIpAhKASIvBXMIxlH/Zljo4EcBUvRsl7e7vkgYMZC/Ua554E0An98j8iEFAEyh6CwNQYxrIP+zKH6ERATanhHtP46M2sgxydurRMdeeRAM+Ed8tD4gcNAV6g53zf1BjGsg/7Mgdz3ZcAeqbTo158fiRtP/SMsPAnEYYU3sAz6L+EV/IQeY0ijFnAko+I1lYwhvZhX+ZgLuZsW0BVqalRUx6ckA7lVMH3WMCqhSSEU+A3UhBTOgIWEBp3cOzDvszBXMzZlgCiHcwL8ekbho1UYIAKHoqinfirFlIaKAJJEDfVQKTnYlq7jWMf9mUO5mJO5l5TgNKXDDW3H/bAk7GFcqD0hnGTJTGFWatqdiRRVIS8dheWjDmYizmZW60lgACHt0EemVAOkdFJknubYbtY+nn+jl+ZxobltsQzF3MyN+9xV7cNF4f0YahVBkKlLp6UmeI+Kp4qvX5afjEkCjLloO/QK/rnXxe+pU6gqBiiZUt30Vl/UiHOxsvXLCGeJ+4b4nYEeHBLqVMHLKu4zzWROAmodmC2MEP4SA32Izu6W1u62K/nWuGZizmZm/fgvUTzlWw5US8Nm3JmMuMgQzOlVj2jn3pUSl0mRmY/RveecT2X2TWMq++8Te0QQtj39uSSzdKuk5aD+Uoy80cUX8gY4geTaiRPX2ezk92WMZaTWIiTNV9jyo8gM1m4xcZt2t1WRLrgIi6XIdzW10x6gGNMSkwKyzi7EM/S3pdlKpv7YCJvHf/wURvKVrApXKm1LC1h+SU4jgV7eBddk+qof/Mloks/IpNPI+W29nU5fY7CU90GbgRq8Eo9LplpQ4w/QZeaJBVhgaIr2rnKOGlUzn8BZ/7iynXg6mUYhfRqoP/lzU7p7aUs8Z7pJTEuHisOHe1z8FUPvUljhfY+lVkl9VdSXVrp5QyxUWjR5pe2FBCLVC43fRwTj1Mb0kVypBbrLtqQb3XqYkGZhCPw+98CDACt/EZVMWT0ogAAAABJRU5ErkJggg==';
  99. const delay = ms => new Promise(res => setTimeout(res, ms));
  100.  
  101. (function () {
  102. 'use strict';
  103. //Bootstrap
  104. function bootstrap(tries = 1) {
  105. if (W && W.loginManager && W.map && W.loginManager.user && W.model && W.model.states && W.model.states.getObjectArray().length && WazeWrap && WazeWrap.Ready) {
  106. if (!OpenLayers.Icon) {
  107. installIcon();
  108. }
  109. init();
  110. //getFeed("http://72.167.49.86:8080/user?user=" + W.loginManager.user.userName, "text", "");
  111. console.log("WME DOT Cameras Loaded!");
  112. } else if (tries < 1000) {
  113. setTimeout(function () {
  114. bootstrap(++tries);
  115. }, 200);
  116. }
  117. }
  118. //Build the Tab and Settings Division
  119. function init() {
  120. var $section = $("<div id=WMEDOTCameraPanel>");
  121. $section.html([
  122. '<div id="chkCameraEnables">',
  123. '<a href="https://www.waze.com/forum/viewtopic.php?f=819&t=304760" target="_blank">WME DOT Cameras</a> v' + GM_info.script.version + '<br>',
  124. '<div id="chkSettings">',
  125. '<table border=1 style="text-align:center;width:90%;padding:10px;">',
  126. '<tr><td width=80 style="text-align:center"><b>Enable</b></td><td style="text-align:center"><b>Setting</b></td></tr>',
  127. '<tr><td align=center><input type="checkbox" id="chkHideZoomOut" class="wmeDOTCamSettings"></td><td align=center>',
  128. 'Hide at zoom: <select class="wmeDOTCamSettings" id="valueHideZoomLevelCam">',
  129. '<option value=12>12</option>',
  130. '<option value=13>13</option>',
  131. '<option value=14>14</option>',
  132. '<option value=15>15</option>',
  133. '<option value=16>16</option>',
  134. '<option value=17>17</option>',
  135. '<option value=18>18</option>',
  136. '</select>',
  137. '</td></tr>',
  138. '</table>',
  139. '</div><br>',
  140. '<table border=1 style="text-align:center;width:90%;padding:10px;">',
  141. '<tr><td width=80 style="text-align:center"><b>Enable</b></td><td style="text-align:center"><b>State</b></td></tr>',
  142. '<tr><td align=center><input type="checkbox" id="chkAKCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>AK</td></tr>',
  143. '<tr><td align=center><input type="checkbox" id="chkALCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>AL</td></tr>',
  144. '<tr><td align=center><input type="checkbox" id="chkARCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>AR</td></tr>',
  145. '<tr><td align=center><input type="checkbox" id="chkAZCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>AZ</td></tr>',
  146. '<tr><td align=center><input type="checkbox" id="chkCACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>CA</td></tr>',
  147. '<tr><td align=center><input type="checkbox" id="chkCOCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>CO</td></tr>',
  148. '<tr><td align=center><input type="checkbox" id="chkCTCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>CT</td></tr>',
  149. '<tr><td align=center><input type="checkbox" id="chkDCCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>DC</td></tr>',
  150. '<tr><td align=center><input type="checkbox" id="chkDECamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>DE</td></tr>',
  151. '<tr><td align=center><input type="checkbox" id="chkFLCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>FL</td></tr>',
  152. '<tr><td align=center><input type="checkbox" id="chkGACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>GA</td></tr>',
  153. '<tr><td align=center><input type="checkbox" id="chkHICamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>HI</td></tr>',
  154. '<tr><td align=center><input type="checkbox" id="chkIACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>IA</td></tr>',
  155. '<tr><td align=center><input type="checkbox" id="chkIDCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>ID</td></tr>',
  156. '<tr><td align=center><input type="checkbox" id="chkILCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>IL</td></tr>',
  157. '<tr><td align=center><input type="checkbox" id="chkINCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>IN</td></tr>',
  158. '<tr><td align=center><input type="checkbox" id="chkKSCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>KS</td></tr>',
  159. '<tr><td align=center><input type="checkbox" id="chkKYCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>KY</td></tr>',
  160. '<tr><td align=center><input type="checkbox" id="chkLACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>LA</td></tr>',
  161. '<tr><td align=center><input type="checkbox" id="chkMACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MA</td></tr>',
  162. '<tr><td align=center><input type="checkbox" id="chkMDCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MD</td></tr>',
  163. '<tr><td align=center><input type="checkbox" id="chkMICamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MI</td></tr>',
  164. '<tr><td align=center><input type="checkbox" id="chkMNCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MN</td></tr>',
  165. '<tr><td align=center><input type="checkbox" id="chkMOCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MO</td></tr>',
  166. '<tr><td align=center><input type="checkbox" id="chkMSCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MS</td></tr>',
  167. '<tr><td align=center><input type="checkbox" id="chkMTCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>MT</td></tr>',
  168. '<tr><td align=center><input type="checkbox" id="chkNCCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>NC</td></tr>',
  169. '<tr><td align=center><input type="checkbox" id="chkNDCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>ND</td></tr>',
  170. '<tr><td align=center><input type="checkbox" id="chkNECamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>NE</td></tr>',
  171. '<tr><td align=center><input type="checkbox" id="chkNWCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>New England (NH, VT, ME)</td></tr>',
  172. '<tr><td align=center><input type="checkbox" id="chkNJCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>NJ</td></tr>',
  173. '<tr><td align=center><input type="checkbox" id="chkNMCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>NM</td></tr>',
  174. '<tr><td align=center><input type="checkbox" id="chkNVCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>NV</td></tr>',
  175. '<tr><td align=center><input type="checkbox" id="chkNYCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>NY</td></tr>',
  176. '<tr><td align=center><input type="checkbox" id="chkOHCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>OH</td></tr>',
  177. '<tr><td align=center><input type="checkbox" id="chkOKCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>OK</td></tr>',
  178. '<tr><td align=center><input type="checkbox" id="chkORCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>OR</td></tr>',
  179. '<tr><td align=center><input type="checkbox" id="chkPACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>PA</td></tr>',
  180. '<tr><td align=center><input type="checkbox" id="chkQCCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>QC</td></tr>',
  181. '<tr><td align=center><input type="checkbox" id="chkRICamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>RI</td></tr>',
  182. '<tr><td align=center><input type="checkbox" id="chkSCCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>SC</td></tr>',
  183. '<tr><td align=center><input type="checkbox" id="chkSDCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>SD</td></tr>',
  184. '<tr><td align=center><input type="checkbox" id="chkTNCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>TN</td></tr>',
  185. '<tr><td align=center><input type="checkbox" id="chkTXCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>TX</td></tr>',
  186. '<tr><td align=center><input type="checkbox" id="chkUTCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>UT</td></tr>',
  187. '<tr><td align=center><input type="checkbox" id="chkVACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>VA</td></tr>',
  188. '<tr><td align=center><input type="checkbox" id="chkWACamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>WA</td></tr>',
  189. '<tr><td align=center><input type="checkbox" id="chkWICamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>WI</td></tr>',
  190. '<tr><td align=center><input type="checkbox" id="chkWVCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>WV</td></tr>',
  191. '<tr><td align=center><input type="checkbox" id="chkWYCamEnabled" class="wmeDOTCamCheckbox"></td><td align=center>WY</td></tr>',
  192. '</table>',
  193. '</div>'
  194. ].join(' '));
  195. WazeWrap.Interface.Tab('DOT Cameras', $section.html(), initializeSettings, '<span title="DOT Cameras">DOT Cameras</span>');
  196. if (showUpdate) {
  197. WazeWrap.Interface.ShowScriptUpdate("WME DOT Cameras", GM_info.script.version, updateMessage, "https://greasyfork.org/en/scripts/407690-wme-dot-cameras", "https://www.waze.com/forum/viewtopic.php?f=819&t=304760");
  198. }
  199. getBounds();
  200. W.map.events.register("moveend", W.map, function () {
  201. if (localsettings.enabled) {
  202. getBounds();
  203. redrawCams();
  204. }
  205. });
  206. $('#chkHideZoomOut').change(function () {
  207. redrawCams();
  208. });
  209. $('#valueHideZoomLevelCam').change(function () {
  210. redrawCams();
  211. //saveSettings();
  212. });
  213. }
  214. function setEnabled(value) {
  215. settings.enabled = value;
  216. saveSettings();
  217. const color = value ? '#00bd00' : '#ccc';
  218. $('span#dot-cameras-power-btn').css({ color });
  219. for (var i = 0; i < stateLength; i++) {
  220. state = document.getElementsByClassName("wmeDOTCamCheckbox")[i].id.replace("chk", "").replace("CamEnabled", "");
  221. if (W.map.getLayersByName(state + 'Layer').length != "0") {
  222. eval(state + 'Layer.setVisibility(' + value + ')');
  223. }
  224. }
  225. }
  226. function getBounds() {
  227. mapBounds = new OpenLayers.Bounds(W.map.getExtent());
  228. mapBounds = mapBounds.transform(new OpenLayers.Projection("EPSG:900913"), new OpenLayers.Projection("EPSG:3857"));
  229. return mapBounds;
  230. }
  231.  
  232. //Load the CSS
  233. GM_xmlhttpRequest({
  234. method: "GET",
  235. url: 'http://72.167.49.86:8080/CSS',
  236. onload: function (response) {
  237. var result = response.responseText;
  238. GM_addStyle(result);
  239. }
  240. });
  241.  
  242. //Build the State Layers
  243. function buildDOTCamLayers(state) {
  244. eval(state.substring(0, 2) + 'Layer = new OpenLayers.Layer.Markers("' + state.substring(0, 2) + 'Layer")');
  245. eval('W.map.addLayer(' + state.substring(0, 2) + 'Layer)');
  246. //eval(state + "Layer.setZIndex(" + newZIndex + ")");
  247. W.map.getOLMap().setLayerIndex(eval(state.substring(0, 2) + 'Layer'), 10);
  248. }
  249. function getFeed(url, type, headers, callback) {
  250. GM_xmlhttpRequest({
  251. method: "GET",
  252. headers: { headers },
  253. url: url,
  254. onload: function (response) {
  255. var result = response.responseText;
  256. callback(result);
  257. }
  258. });
  259. }
  260. async function redrawCams() {
  261. await W.map.getZoom();
  262. for (const property in settings) {
  263. let state = property.replace("chk", "").replace("CamEnabled", "");
  264. if (state.length == 2) {
  265. if (document.getElementById('chk' + state + 'CamEnabled').checked && (W.map.getLayersByName(state + 'Layer').length == 1)) {
  266. eval('W.map.removeLayer(' + state + 'Layer)');
  267. buildDOTCamLayers(state);
  268. eval('testCam(' + state + 'Feed, config.' + state + ')');
  269. if (W.map.getZoom() >= 12) {
  270. if (document.getElementById('chkHideZoomOut').checked) {
  271. if (W.map.getZoom() > document.getElementById('valueHideZoomLevelCam').value) {
  272. eval(state + 'Layer.setVisibility(true)');
  273. } else {
  274. eval(state + 'Layer.setVisibility(false)');
  275. console.log("disabling " + state);
  276. }
  277. } else {
  278. eval(state + 'Layer.setVisibility(true)');
  279. }
  280. } else {
  281. eval(state + 'Layer.setVisibility(false)');
  282. }
  283. }
  284. }
  285. }
  286. }
  287. function getCam(state) {
  288. let j = 0;
  289. while (j < state.URL.length) {
  290. console.log(state.URL);
  291. getFeed(state.URL[j], "json", "", function (res) {
  292. let resultObj = [];
  293. if (state.x) {
  294. resultObj = state.x(x2js.xml_str2json(res));
  295. } else if (state.y) {
  296. resultObj = state.y(JSON.parse(res.toString().match(/(?<=camera_data = )[\s\S]*/)));
  297. } else {
  298. resultObj = state.data(JSON.parse(res));
  299. }
  300. eval(state.scheme(resultObj[1]).state + 'Feed = resultObj');
  301. testCam(resultObj, state);
  302. if (localsettings.enabled) {
  303. if (document.getElementById('chkHideZoomOut').checked) {
  304. if (W.map.getZoom() > document.getElementById('valueHideZoomLevelCam').value) {
  305. eval(state.scheme(resultObj[1]).state + 'Layer.setVisibility(true)');
  306. } else {
  307. eval(state.scheme(resultObj[1]).state + 'Layer.setVisibility(false)');
  308. }
  309. }
  310. else {
  311. eval(state.scheme(resultObj[1]).state + 'Layer.setVisibility(true)');
  312. }
  313. }
  314. });
  315. j++;
  316. }
  317. }
  318. function testCam(resultObj, state) {
  319. let i = 0;
  320. while (i < resultObj.length) {
  321. if ((state.scheme(resultObj[i]).lon > mapBounds.left) && (state.scheme(resultObj[i]).lon < mapBounds.right)) {
  322. if ((state.scheme(resultObj[i]).lat > mapBounds.bottom) && (state.scheme(resultObj[i]).lat < mapBounds.top)) {
  323. drawCam(state.scheme(resultObj[i]));
  324. }
  325. }
  326. i++;
  327. }
  328. }
  329. function drawCam(spec) {
  330. var icon;
  331. var size = new OpenLayers.Size(20, 20);
  332. if (spec.enabled == false) {
  333. icon = new OpenLayers.Icon(camRed, size);
  334. } else {
  335. icon = new OpenLayers.Icon(camIcon, size);
  336. }
  337. var offset = new OpenLayers.Pixel(-(size.w / 2), -size.h);
  338. var epsg4326 = new OpenLayers.Projection("EPSG:4326"); //WGS 1984 projection
  339. var projectTo = W.map.getProjectionObject(); //The map projection (Spherical Mercator)
  340. var lonLat = new OpenLayers.LonLat(spec.lon, spec.lat).transform(epsg4326, projectTo);
  341. var newMarker = new OpenLayers.Marker(lonLat, icon);
  342. newMarker.title = spec.desc;
  343. if (spec.subtitle != undefined) {
  344. newMarker.subtitle = spec.subtitle;
  345. } else { newMarker.subtitle = ""; }
  346. newMarker.id = spec.id;
  347. newMarker.url = spec.src;
  348. newMarker.width = spec.width;
  349. newMarker.height = spec.height;
  350. newMarker.state = spec.state;
  351. newMarker.camType = spec.camType;
  352. newMarker.location = lonLat;
  353. //newMarker.setOpacity(.8);
  354. newMarker.events.register('click', newMarker, popupCam);
  355. eval(spec.state + 'Layer.addMarker(newMarker)');
  356. }
  357. //Generate the Camera Popup
  358. function popupCam(evt) {
  359. //Code to check if WME Toolbox is running, and if it is, go no further (hopefully temporary!) - Fixed 10-Dec-2020 but I'm leaving the code here because I don't trust TB yet :P
  360. //var i = 0;
  361. //while (i < document.getElementsByTagName('script').length) {
  362. //if (document.getElementsByTagName('script')[i].src == "chrome-extension://ihebciailciabdiknfomleeccodkdejn/scripts/WME_Toolbox.prod.min.js") {
  363. //alert("WME DOT Cameras cannot run if Toolbox is enabled, due to current issues with the Toolbox extension. Please disable the Toolbox extension in order to use this script until the issue is resolved.");
  364. //return;
  365. //}
  366. //i++;
  367. //}
  368. clearInterval(staticUpdateID);
  369. $("#gmPopupContainerCam").remove();
  370. $("#gmPopupContainerCam").hide();
  371. W.map.moveTo(this.location);
  372. var popupHTML = [];
  373. var titleNC = "";
  374.  
  375. popupHTML[0] = (['<div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100">' +
  376. '<a href="#close" id="gmCloseCamDlgBtn" title="Close" class="modelCloseCam" style="color:#FF0000;">X</a>' +
  377. '<table border=0><tr><td><div id="mycamdivheader" style="min-height: 20px;">' + this.title + '</div></td></tr>' +
  378. '<tr><td><div id="videoDiv">' +
  379. '<video id="hlsVideo" width=' + this.width + ' height=' + this.height + ' controls autoplay></video>' +
  380. '</div></td></tr>' +
  381. '</table></div>'
  382. ]);
  383. popupHTML[1] = (['<div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100">' +
  384. '<a href="#close" id="gmCloseCamDlgBtn" title="Close" class="modelCloseCam" style="color:#FF0000;">X</a>' +
  385. '<table border=0><tr><td><div id="mycamdivheader" style="min-height: 20px;">' + this.title + '</div></td></tr>' +
  386. '<tr><td><center>' + this.title + '</td></tr>' +
  387. '<tr><td><a href="' + this.url + '" id="camType1href" target="_blank"><img src="' + this.url + '" style="width:400px" id="staticimage"></a></td></tr>' +
  388. '</table></div>'
  389. ]);
  390. let metaHead = `<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *;**script-src 'self' http://onlineerp.solution.quebec 'unsafe-inline' 'unsafe-eval';** "></meta>`;
  391. popupHTML[2] = (['<div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100">' +
  392. '<a href="#close" id="gmCloseCamDlgBtn" title="Close" class="modelCloseCam" style="color:#FF0000;">X</a>' +
  393. '<table border=0><tr><td><div id="mycamdivheader" style="min-height: 20px;">' + this.title + '</div></td></tr>' +
  394. '<tr><td><center>' + this.subtitle + '</td></tr>' +
  395. '<tr><td><div id="videoDiv">' +
  396. '<video id="hlsVideo" width=' + this.width + ' height=' + this.height + ' controls autoplay style="width:400px"></video>' +
  397. '</div></td></tr>' +
  398. '</table></div>'
  399. ]);
  400. popupHTML[3] = popupHTML[2];
  401. popupHTML[4] = (['<div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100">' +
  402. '<a href="#close" id="gmCloseCamDlgBtn" title="Close" class="modelCloseCam" style="color:#FF0000;">X</a>' +
  403. '<table border=0><tr><td><div id="mycamdivheader" style="min-height: 20px;"></div></td></tr>' +
  404. '<tr><td><center><h4><div id="titleNC" >' + titleNC + '</div></h4></td></tr>' +
  405. '<tr><td><a href="" id="camType4href" target="_blank"><img src="' + this.url + '" style="width:400px" id="staticimage"></a></td></tr>' +
  406. '</table></div>'
  407. ]);
  408. popupHTML[5] = (['<div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100">' +
  409. '<a href="#close" id="gmCloseCamDlgBtn" title="Close" class="modelCloseCam" style="color:#FF0000;">X</a>' +
  410. '<table border=0><tr><td><div id="mycamdivheader" style="min-height: 20px;"></div></td></tr>' +
  411. '<tr><td><center><h4>' + this.title + '</h4></td></tr>' +
  412. '<tr><td><a href="' + this.url + '" target="_blank">Click here to view image</a></td></tr>' +
  413. '</table></div>'
  414. ]);
  415. popupHTML[6] = (['<div id="gmPopupContainerCam" style="position: fixed;padding: 10px;z-index: 1100;background: #fefefe;border-radius: 12px;">' +
  416. '<div style="padding: 5px;"><h4 style="display: inline-block;">' +
  417. '<div id="titleNC">' + titleNC + '</div></h4>' +
  418. '<a href="#close" id="gmCloseCamDlgBtn" title="Close" class="modelCloseCam" style="float: right;text-decoration: none;font-size: 24px;line-height: 24px;">✖</a>' +
  419. '</div><img src="' + this.url + '" style="width:400px;border-radius: 6px;" id="staticimage"></div>'
  420. ]);
  421. var currentCamURL = this.url;
  422. switch (this.camType) {
  423. case 0:
  424. $("body").append(popupHTML[0]);
  425. setTimeout(function () {
  426. video = document.getElementById('hlsVideo');
  427. var videoSrc = currentCamURL;
  428. if (hls) { hls.destroy(); }
  429. if (Hls.isSupported()) {
  430. //console.log('Loading video from ' + videoSrc);
  431. hls = new Hls();
  432. hls.loadSource(videoSrc);
  433. hls.attachMedia(video);
  434. hls.on(Hls.Events.MANIFEST_PARSED, function () {
  435. video.play();
  436. });
  437. }
  438. }, 1000);
  439. break;
  440. case 1:
  441. $("body").append(popupHTML[1]);
  442. staticUpdateID = setInterval(function () {
  443. var camImage = document.getElementById('staticimage');
  444. if (currentCamURL.includes('?')) {
  445. camImage.src = `${currentCamURL}&rand=${Math.random()}`;
  446. document.getElementById('camType1href').href = camImage.src;
  447. }
  448. else {
  449. camImage.src = currentCamURL + '?rand=' + Math.random();
  450. document.getElementById('camType1href').href = camImage.src;
  451. }
  452. }, 2000);
  453. break;
  454. case 2:
  455. $("body").append(popupHTML[2]);
  456. console.log(paToken);
  457. if (paToken == "") {
  458. GM_xmlhttpRequest({
  459. method: "GET",
  460. headers: {
  461. "Referer": "https://www.511pa.com",
  462. "Accept": "/"
  463. },
  464. url: "https://www.511pa.com/Camera/GetVideoUrl?cameraId=" + this.id + "--10&_=" + Date.now(),
  465. onload: function (response) {
  466. let result = response.responseText;
  467. console.log(result);
  468. GM_xmlhttpRequest({
  469. method: "POST",
  470. headers: {
  471. "Referer": "https://www.511pa.com/",
  472. "Accept": "*/*",
  473. "Content-Length": "93",
  474. "Content-Type": "application/json",
  475. "Origin": "https://www.511pa.com",
  476. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
  477. },
  478. data: result,
  479. url: "https://pa.arcadis-ivds.com/api/SecureTokenUri/GetSecureTokenUriBySourceId",
  480. onload: function (response) {
  481. let result = response.responseText;
  482. console.log(result);
  483. paToken = result.replaceAll('"', '');
  484. loadPACam();
  485. }
  486. });
  487. }
  488. });
  489. } else {
  490. loadPACam();
  491. }
  492. function loadPACam() {
  493. setTimeout(async function () {
  494. video = document.getElementById('hlsVideo');
  495. var videoSrc = currentCamURL + paToken;
  496. if (hls) { hls.destroy(); }
  497. if (Hls.isSupported()) {
  498. //console.log('Loading camera video from ' + videoSrc);
  499. hls = await new Hls();
  500. await hls.loadSource(videoSrc);
  501. await delay(1000);
  502. await hls.attachMedia(video);
  503. hls.on(Hls.Events.MANIFEST_PARSED, function () {
  504. video.play();
  505. });
  506. }
  507. }, 500);
  508. }
  509. break;
  510. case 3:
  511. $("body").append(popupHTML[3]);
  512. let id;
  513. if (currentCamURL.includes("njtpk-wink")) {
  514. id = 1;
  515. } else { id = 2; }
  516. var token;
  517. getFeed('https://www.njta.com/api/video', 'xml', "", function (res) {
  518. token = res.replace(/["]/g, "");
  519.  
  520.  
  521. getFeed('https://publicmap1.511nj.org/api/client/camera/getHlsToken?Id=' + id, 'json', "", function (res) {
  522. currentCamURL = currentCamURL + "?otp=" + token; //JSON.parse(res).Data.Token;
  523.  
  524. setTimeout(function () {
  525. video = document.getElementById('hlsVideo');
  526. var videoSrc = currentCamURL;
  527. if (hls) { hls.destroy(); }
  528. if (Hls.isSupported()) {
  529. hls = new Hls({
  530. xhrSetup: xhr => {
  531. xhr.setRequestHeader('If-None-Since', "Wed, 06 Jul 2022 00:31:33 GMT");
  532. xhr.setRequestHeader('If-None-Match', "228d1d4629c1f1e35e68d5cbb30d147802afad4e85c32ce52760a59a6937a8a9");
  533. xhr.setRequestHeader('access-control-allow-origin', '*');
  534. }
  535. });
  536. hls.loadSource(videoSrc);
  537. hls.attachMedia(video);
  538. hls.on(Hls.Events.MANIFEST_PARSED, function () {
  539. video.play();
  540. });
  541. }
  542. }, 1000);
  543. });
  544. });
  545. break;
  546. case 4:
  547. $("body").append(popupHTML[4]);
  548. getFeed('https://eapps.ncdot.gov/services/traffic-prod/v1/cameras/' + currentCamURL, 'json', "", function (res) {
  549. currentCamURL = JSON.parse(res).imageURL;
  550. titleNC = JSON.parse(res).locationName;
  551. document.getElementById("titleNC").innerHTML = titleNC;
  552. staticUpdateID = setInterval(function () {
  553. var camImage = document.getElementById('staticimage');
  554. if (currentCamURL.includes('?')) {
  555. camImage.src = `${currentCamURL}&rand=${Math.random()}`;
  556. document.getElementById('camType4href').href = camImage.src;
  557. }
  558. else {
  559. camImage.src = currentCamURL + '?rand=' + Math.random();
  560. document.getElementById('camType4href').href = camImage.src;
  561. }
  562. }, 100);
  563. });
  564. break;
  565. case 5:
  566. $("body").append(popupHTML[5]);
  567. staticUpdateID = setInterval(function () {
  568. var camImage = document.getElementById('staticimage');
  569. if (currentCamURL.includes('?')) { camImage.src = `${currentCamURL}&rand=${Math.random()}`; }
  570. else { camImage.src = currentCamURL + '?rand=' + Math.random(); }
  571. }, 5000);
  572. break;
  573. case 6:
  574. $("body").append(popupHTML[6]);
  575. getFeed(`https://its.txdot.gov/its/DistrictIts/GetCctvSnapshotByIcdId?icdId=${currentCamURL[0]}&districtCode=${currentCamURL[1]}`, 'json', "", function (res) {
  576. titleNC = currentCamURL[0];
  577. currentCamURL = "data:image/jpeg;base64," + JSON.parse(res).snippet;
  578. document.getElementById("titleNC").innerHTML = titleNC;
  579. var camImage = document.getElementById('staticimage');
  580. camImage.src = currentCamURL;
  581. document.getElementById('camType4href').href = camImage.src;
  582. });
  583. break;
  584. }
  585. //Position the modal based on the position of the click event
  586. $("#gmPopupContainerCam").css({ left: document.getElementById("user-tabs").offsetWidth + W.map.getPixelFromLonLat(W.map.getUnprojectedCenter()).x - document.getElementById("gmPopupContainerCam").clientWidth - 10 });
  587. $("#gmPopupContainerCam").css({ top: document.getElementById("left-app-head").offsetHeight + W.map.getPixelFromLonLat(W.map.getUnprojectedCenter()).y - (document.getElementById("gmPopupContainerCam").clientHeight / 2) });
  588. //Add listener for popup's "Close" button
  589. $("#gmCloseCamDlgBtn").click(function () {
  590. if (hls) {
  591. hls.destroy();
  592. }
  593. clearInterval(staticUpdateID);
  594. $("#gmPopupContainerCam").remove();
  595. $("#gmPopupContainerCam").hide();
  596. });
  597. dragElement(document.getElementById("gmPopupContainerCam"));
  598. setTimeout(function () {
  599. fetch(currentCamURL)
  600. .then(response => {
  601. if (!response.ok) {
  602. //Bad feed
  603. $('#videoDiv').empty();
  604. document.getElementById('videoDiv').innerHTML = "<br>Sorry, this feed is currently offline.";
  605. } else {
  606. //Good Feed
  607. }
  608. });
  609. }, 1500);
  610. }
  611. // Make the DIV element draggable:
  612. function dragElement(elmnt) {
  613. var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  614. if (document.getElementById("mycamdivheader")) {
  615. // if present, the header is where you move the DIV from:
  616. document.getElementById("mycamdivheader").onmousedown = dragMouseDown;
  617. } else {
  618. // otherwise, move the DIV from anywhere inside the DIV:
  619. elmnt.onmousedown = dragMouseDown;
  620. }
  621.  
  622. function dragMouseDown(e) {
  623. e = e || window.event;
  624. e.preventDefault();
  625. // get the mouse cursor position at startup:
  626. pos3 = e.clientX;
  627. pos4 = e.clientY;
  628. document.onmouseup = closeDragElement;
  629. // call a function whenever the cursor moves:
  630. document.onmousemove = elementDrag;
  631. }
  632.  
  633. function elementDrag(e) {
  634. e = e || window.event;
  635. e.preventDefault();
  636. // calculate the new cursor position:
  637. pos1 = pos3 - e.clientX;
  638. pos2 = pos4 - e.clientY;
  639. pos3 = e.clientX;
  640. pos4 = e.clientY;
  641. // set the element's new position:
  642. elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
  643. elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  644. }
  645.  
  646. function closeDragElement() {
  647. // stop moving when mouse button is released:
  648. document.onmouseup = null;
  649. document.onmousemove = null;
  650. }
  651. }
  652. //Initialize Settings
  653. function initializeSettings() {
  654. stateLength = document.getElementsByClassName("wmeDOTCamCheckbox").length;
  655. loadSettings();
  656. //Set the state checkboxes according to saved settings
  657. for (var i = 0; i < stateLength; i++) {
  658. state = document.getElementsByClassName("wmeDOTCamCheckbox")[i].id.replace("chk", "").replace("CamEnabled", "");
  659. setChecked('chk' + state + 'CamEnabled', eval('settings.' + state + 'CamEnabled'));
  660. }
  661. for (var i = 0; i < document.getElementsByClassName("wmeDOTCamSettings").length; i++) {
  662. settingID = document.getElementsByClassName("wmeDOTCamSettings")[i].id;
  663. if (document.getElementsByClassName("wmeDOTCamSettings")[i].type == "checkbox") {
  664. setChecked(settingID, eval('settings.' + settingID));
  665. } else if (document.getElementsByClassName("wmeDOTCamSettings")[i].type == "select-one") {
  666. document.getElementById('valueHideZoomLevelCam').value = eval('settings.' + settingID);
  667. //alert(document.getElementById('valueHideZoomLevelCam').value + " : " + eval('settings.' + settingID));
  668. //$("#valueHideZoomLevelCam").val(eval('settings.' + settingID)).change();
  669.  
  670. }
  671. }
  672. //Build the layers for the selected states
  673. for (var i = 0; i < stateLength; i++) {
  674. state = document.getElementsByClassName("wmeDOTCamCheckbox")[i].id.replace("chk", "").replace("CamEnabled", "");
  675. if (document.getElementById('chk' + state + 'CamEnabled').checked) { buildDOTCamLayers(state); eval('getCam(config.' + state + ')'); }
  676. }
  677. document.getElementById('chkFLCamEnabled').disabled = true; // need to figure out tokens
  678. document.getElementById('chkARCamEnabled').disabled = true; // need to figure out tokens
  679. //document.getElementById('chkTXCamEnabled').disabled = true; // not working
  680.  
  681.  
  682. //Add Handler for Checkbox Setting Changes
  683. $('.wmeDOTCamCheckbox').change(function () {
  684. var settingName = $(this)[0].id.substr(3);
  685. settings[settingName] = this.checked;
  686. saveSettings();
  687. if (this.checked) {
  688. buildDOTCamLayers(settingName.substring(0, 2));
  689. eval("getCam(config." + settingName.substring(0, 2) + ")");
  690. } else {
  691. //eval(settingName.substring(0, 2) + "Layer.destroy()");
  692. eval('W.map.removeLayer(' + settingName.substring(0, 2) + 'Layer)');
  693. }
  694. });
  695. $('.wmeDOTCamSettings').change(function () {
  696. var settingName = $(this)[0].id;
  697. settings[settingName] = this.checked;
  698. saveSettings();
  699. });
  700. setEnabled(localsettings.enabled);
  701. }
  702. //Set Checkbox from Settings
  703. function setChecked(checkboxId, checked) {
  704. $('#' + checkboxId).prop('checked', checked);
  705. }
  706. //Load Saved Settings
  707. function loadSettings() {
  708. if (!localStorage.Camera_Settings) {
  709. localsettings.enabled = true;
  710. localStorage.setItem("Camera_Settings", JSON.stringify(localsettings));
  711. }
  712. localsettings = $.parseJSON(localStorage.getItem("Camera_Settings"));
  713. var defaultSettings = { Enabled: false, };
  714. settings = localsettings ? localsettings : defaultSettings;
  715. for (var prop in defaultSettings) {
  716. if (!settings.hasOwnProperty(prop)) {
  717. settings[prop] = defaultSettings[prop];
  718. }
  719. }
  720. const color = localsettings.enabled ? '#00bd00' : '#ccc';
  721. $('span[title="DOT Cameras"]').prepend(
  722. $('<span>', {
  723. class: 'fa fa-power-off',
  724. id: 'dot-cameras-power-btn',
  725. style: `margin-right: 5px;cursor: pointer;color: ${color};font-size: 13px;`,
  726. title: 'Toggle DOT Cameras'
  727. }).click(evt => {
  728. evt.stopPropagation();
  729. setEnabled(!localsettings.enabled);
  730. })
  731. );
  732. }
  733. //Save Tab Settings
  734. function saveSettings() {
  735. if (localStorage) {
  736. for (var i = 0; i < stateLength; i++) {
  737. state = document.getElementsByClassName("wmeDOTCamCheckbox")[i].id.replace("chk", "").replace("CamEnabled", "");
  738. eval('localsettings.' + state + 'CamEnabled = document.getElementsByClassName("wmeDOTCamCheckbox")[i].checked');
  739. }
  740. for (var i = 0; i < document.getElementsByClassName("wmeDOTCamSettings").length; i++) {
  741. if (document.getElementsByClassName("wmeDOTCamSettings")[i].type == "checkbox") {
  742. settingID = document.getElementsByClassName("wmeDOTCamSettings")[i].id;
  743. eval('localsettings.' + settingID + ' = document.getElementsByClassName("wmeDOTCamSettings")[i].checked');
  744. } else if (document.getElementsByClassName("wmeDOTCamSettings")[i].type == "select-one") {
  745. settingID = document.getElementsByClassName("wmeDOTCamSettings")[i].id;
  746. eval('localsettings.' + settingID + ' = document.getElementsByClassName("wmeDOTCamSettings")[i].value');
  747. }
  748. }
  749. localStorage.setItem("Camera_Settings", JSON.stringify(localsettings));
  750. }
  751. }
  752. //Add the Icon Class to OpenLayers
  753. function installIcon() {
  754. console.log('Installing OpenLayers.Icon');
  755. OpenLayers.Icon = OpenLayers.Class({
  756. url: null,
  757. size: null,
  758. offset: null,
  759. calculateOffset: null,
  760. imageDiv: null,
  761. px: null,
  762. initialize: function (a, b, c, d) {
  763. this.url = a;
  764. this.size = b || {
  765. w: 20,
  766. h: 20
  767. };
  768. this.offset = c || {
  769. x: -(this.size.w / 2),
  770. y: -(this.size.h / 2)
  771. };
  772. this.calculateOffset = d;
  773. a = OpenLayers.Util.createUniqueID("OL_Icon_");
  774. let div = this.imageDiv = OpenLayers.Util.createAlphaImageDiv(a);
  775. $(div.firstChild).removeClass('olAlphaImg'); // LEAVE THIS LINE TO PREVENT WME-HARDHATS SCRIPT FROM TURNING ALL ICONS INTO HARDHAT WAZERS --MAPOMATIC
  776. },
  777. destroy: function () {
  778. this.erase();
  779. OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
  780. this.imageDiv.innerHTML = "";
  781. this.imageDiv = null;
  782. },
  783. clone: function () {
  784. return new OpenLayers.Icon(this.url, this.size, this.offset, this.calculateOffset);
  785. },
  786. setSize: function (a) {
  787. null !== a && (this.size = a);
  788. this.draw();
  789. },
  790. setUrl: function (a) {
  791. null !== a && (this.url = a);
  792. this.draw();
  793. },
  794. draw: function (a) {
  795. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, this.size, this.url, "absolute");
  796. this.moveTo(a);
  797. return this.imageDiv;
  798. },
  799. erase: function () {
  800. null !== this.imageDiv && null !== this.imageDiv.parentNode && OpenLayers.Element.remove(this.imageDiv);
  801. },
  802. setOpacity: function (a) {
  803. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, null, null, null, null, a);
  804. },
  805. moveTo: function (a) {
  806. null !== a && (this.px = a);
  807. null !== this.imageDiv && (null === this.px ? this.display(!1) : (
  808. this.calculateOffset && (this.offset = this.calculateOffset(this.size)),
  809. OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {
  810. x: this.px.x + this.offset.x,
  811. y: this.px.y + this.offset.y
  812. })
  813. ));
  814. },
  815. display: function (a) {
  816. this.imageDiv.style.display = a ? "" : "none";
  817. },
  818. isDrawn: function () {
  819. return this.imageDiv && this.imageDiv.parentNode && 11 != this.imageDiv.parentNode.nodeType;
  820. },
  821. CLASS_NAME: "OpenLayers.Icon"
  822. });
  823. }
  824. bootstrap();
  825. const config = {
  826. AK: {
  827. data(res) {
  828. return res;
  829. },
  830. scheme(obj) {
  831. return {
  832. state: "AK",
  833. camType: 1,
  834. lon: obj.Longitude,
  835. lat: obj.Latitude,
  836. src: obj.Url,
  837. desc: obj.Name
  838. };
  839. },
  840. URL: ['http://72.167.49.86:8080/AKCam']
  841. },
  842. AL: {
  843. data(res) {
  844. let cams = [];
  845. let i = 0;
  846. while (i < res.length) {
  847. cams.push(res[i].entries);
  848. i++;
  849. }
  850. return cams.flat();
  851. },
  852. scheme(obj) {
  853. return {
  854. state: "AL",
  855. camType: 0,
  856. lon: obj.longitude,
  857. lat: obj.latitude,
  858. src: obj.streamUrl,
  859. desc: `${obj.primaryRoad} @ ${obj.crossStreet}`,
  860. width: 480,
  861. height: 360
  862. };
  863. },
  864. URL: ['https://algotraffic.com/api/v1/layers/cameras']
  865. },
  866. AR: {
  867. data(res) {
  868. return res.feed.entry;
  869. },
  870. scheme(obj) {
  871. return {
  872. state: "AR",
  873. camType: 0,
  874. lon: obj.lon,
  875. lat: obj.lat,
  876. src: obj.src,
  877. desc: obj.desc,
  878. width: 480,
  879. height: 360
  880. };
  881. },
  882. URL: ['http://72.167.49.86:8080/ARCam']
  883. },
  884. AZ: {
  885. data(res) {
  886. return res;
  887. },
  888. scheme(obj) {
  889. return {
  890. state: "AZ",
  891. camType: 1,
  892. lon: obj.Longitude,
  893. lat: obj.Latitude,
  894. src: obj.Url,
  895. desc: obj.Description
  896. };
  897. },
  898. URL: ['http://72.167.49.86:8080/AZCam']
  899. },
  900. CA: {
  901. data(res) {
  902. return res;
  903. },
  904. scheme(obj) {
  905. return {
  906. state: "CA",
  907. camType: 1,
  908. lon: obj.cctv.location.longitude,
  909. lat: obj.cctv.location.latitude,
  910. src: obj.cctv.imageData.static.currentImageURL,
  911. desc: obj.cctv.location.locationName
  912. };
  913. },
  914. URL: ['http://192.168.50.105:8080/CACam']
  915. },
  916. CO: {
  917. data(res) {
  918. return res;
  919. },
  920. scheme(obj) {
  921. if (obj.streamUrl !== null) {
  922. return {
  923. state: "CO",
  924. camType: 0,
  925. lon: obj.features[0].geometry.coordinates[0],
  926. lat: obj.features[0].geometry.coordinates[1],
  927. src: obj.streamUrl[0].src,
  928. desc: obj.tooltip
  929. };
  930. }
  931. else {
  932. return {
  933. state: "CO",
  934. camType: 1,
  935. lon: obj.features[0].geometry.coordinates[0],
  936. lat: obj.features[0].geometry.coordinates[1],
  937. src: obj.views[0].url,
  938. desc: obj.tooltip
  939. };
  940. }
  941. },
  942. URL: ['http://72.167.49.86:8080/COCam']
  943. },
  944. CT: {
  945. data(res) {
  946. return res;
  947. },
  948. scheme(obj) {
  949. return {
  950. state: "CT",
  951. camType: 1,
  952. lon: obj.location[1],
  953. lat: obj.location[0],
  954. src: `https://cttravelsmart.org/map/Cctv/${obj.itemId}`,
  955. desc: null
  956. };
  957. },
  958. URL: ["http://72.167.49.86:8080/CTCam"]
  959. },
  960. DC: {
  961. data(res) {
  962. return res;
  963. },
  964. scheme(obj) {
  965. return {
  966. state: "DC",
  967. camType: 0,
  968. lon: obj.lng,
  969. lat: obj.lat,
  970. src: 'https://' + obj.host.match(".*(?=\:1935)") + '/rtplive/' + obj.stream + "/playlist.m3u8",
  971. desc: obj.title,
  972. width: 480,
  973. height: 360
  974. };
  975. },
  976. URL: ["http://72.167.49.86:8080/DCCam"]
  977. },
  978. DE: {
  979. data(res) {
  980. return res.videoCameras;
  981. },
  982. scheme(obj) {
  983. return {
  984. state: "DE",
  985. camType: 0,
  986. lon: obj.lon,
  987. lat: obj.lat,
  988. src: obj.urls.m3u8s,
  989. desc: `${obj.title} (${obj.county})`,
  990. width: 550,
  991. height: 300
  992. };
  993. },
  994. URL: ['https://tmc.deldot.gov/json/videocamera.json']
  995. },
  996. FL: {
  997. data(res) {
  998. return res.data;
  999. },
  1000. scheme(obj) {
  1001. return {
  1002. state: "FL",
  1003. camType: 0,
  1004. lon: obj.longitude,
  1005. lat: obj.latitude,
  1006. src: obj.videoUrl,
  1007. desc: obj.description2
  1008. };
  1009. },
  1010. URL: ['https://fl511.com/List/GetData/Cameras?query=%7B%22columns%22%3A%5B%7B%22data%22%3Anull%2C%22name%22%3A%22%22%7D%2C%7B%22name%22%3A%22sortId%22%2C%22s%22%3Atrue%7D%2C%7B%22name%22%3A%22region%22%2C%22s%22%3Atrue%7D%2C%7B%22name%22%3A%22county%22%2C%22s%22%3Atrue%7D%2C%7B%22name%22%3A%22roadway%22%2C%22s%22%3Atrue%7D%2C%7B%22data%22%3A5%2C%22name%22%3A%22description2%22%7D%2C%7B%22data%22%3A6%2C%22name%22%3A%22%22%7D%5D%2C%22order%22%3A%5B%7B%22column%22%3A1%2C%22dir%22%3A%22asc%22%7D%2C%7B%22column%22%3A2%2C%22dir%22%3A%22asc%22%7D%5D%2C%22start%22%3A0%2C%22length%22%3A5000%2C%22search%22%3A%7B%22value%22%3A%22%22%7D%7D&lang=en']
  1011. },
  1012. GA: {
  1013. data(res) {
  1014. return res;
  1015. },
  1016. scheme(obj) {
  1017. /*if (obj.properties.HLS) {return {state: "GA",camType:0,lon:obj.geometry.coordinates[0],lat:obj.geometry.coordinates[1],src:obj.properties.HLS,desc:obj.properties.location_description,width:480,height:360}}
  1018. else {}*/
  1019. let camURL, camType;
  1020. if (obj.VideoUrl != null) {
  1021. camURL = obj.VideoUrl;
  1022. camType = 0;
  1023. } else {
  1024. camURL = obj.Url;
  1025. camType = 1;
  1026. }
  1027. return {
  1028. state: "GA",
  1029. camType: camType,
  1030. lon: obj.Longitude,
  1031. lat: obj.Latitude,
  1032. src: camURL,
  1033. desc: obj.Name
  1034. };
  1035. },
  1036. URL: ['http://72.167.49.86:8080/GACam']
  1037. },
  1038. HI: {
  1039. data(res) {
  1040. return res
  1041. },
  1042. scheme(obj) {
  1043. if (obj.images.length == 4) {
  1044. return {
  1045. state: "HI",
  1046. camType: 0,
  1047. lon: obj.location.coordinates.longitude,
  1048. lat: obj.location.coordinates.latitude,
  1049. src: obj.images[3].URL,
  1050. desc: obj.description
  1051. }
  1052. }
  1053. else {
  1054. return {
  1055. state: "HI",
  1056. camType: 1,
  1057. lon: obj.location.coordinates.longitude,
  1058. lat: obj.location.coordinates.latitude,
  1059. src: obj.images[0].URL,
  1060. desc: obj.description
  1061. }
  1062. }
  1063. },
  1064. URL: ['http://72.167.49.86:8080/HICam']
  1065. },
  1066. IA: {
  1067. data(res) {
  1068. return res.features;
  1069. },
  1070. scheme(obj) {
  1071. if (!obj.attributes.VideoURL) {
  1072. return {
  1073. state: "IA",
  1074. camType: 1,
  1075. lon: obj.geometry.x,
  1076. lat: obj.geometry.y,
  1077. src: obj.attributes.ImageURL,
  1078. desc: obj.attributes.ImageName
  1079. };
  1080. } else {
  1081. return {
  1082. state: "IA",
  1083. camType: 0,
  1084. lon: obj.geometry.x,
  1085. lat: obj.geometry.y,
  1086. src: obj.attributes.VideoURL,
  1087. desc: obj.attributes.ImageName
  1088. };
  1089. }
  1090. },
  1091. URL: ['https://services.arcgis.com/8lRhdTsQyJpO52F1/arcgis/rest/services/Traffic_Cameras_View/FeatureServer/0/query?where=1%3D1&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&returnGeodetic=false&outFields=ImageName%2C+ImageURL%2C+VideoURL&returnGeometry=true&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=4326&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pjson&token=']
  1092. },
  1093. ID: {
  1094. data(res) {
  1095. return res;
  1096. },
  1097. scheme(obj) {
  1098. return {
  1099. state: "ID",
  1100. camType: 1,
  1101. lon: obj.features[0].geometry.coordinates[0],
  1102. lat: obj.features[0].geometry.coordinates[1],
  1103. src: obj.views[0].url,
  1104. desc: obj.tooltip
  1105. };
  1106. },
  1107. URL: ['http://72.167.49.86:8080/IDCam']
  1108. },
  1109. IL: {
  1110. data(res) {
  1111. return res.features;
  1112. },
  1113. scheme(obj) {
  1114. return {
  1115. state: "IL",
  1116. camType: 1,
  1117. lon: obj.attributes.x,
  1118. lat: obj.attributes.y,
  1119. src: obj.attributes.SnapShot,
  1120. desc: obj.attributes.CameraLocation
  1121. };
  1122. },
  1123. URL: ['https://services2.arcgis.com/aIrBD8yn1TDTEXoz/arcgis/rest/services/TrafficCamerasTM_Public/FeatureServer/0//query?where=y+%3E+0&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&returnGeodetic=false&outFields=*&returnGeometry=true&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pjson&token=']
  1124. },
  1125. IN: {
  1126. data(res) {
  1127. return res;
  1128. },
  1129. scheme(obj) {
  1130. return {
  1131. state: "IN",
  1132. camType: 1,
  1133. lon: obj.features[0].geometry.coordinates[0],
  1134. lat: obj.features[0].geometry.coordinates[1],
  1135. src: obj.views[0].url,
  1136. desc: obj.tooltip
  1137. };
  1138. },
  1139. URL: ['http://72.167.49.86:8080/INCam']
  1140. },
  1141. KS: {
  1142. data(res) {
  1143. return res;
  1144. },
  1145. scheme(obj) {
  1146. return {
  1147. state: "KS",
  1148. camType: 1,
  1149. lon: obj.features[0].geometry.coordinates[0],
  1150. lat: obj.features[0].geometry.coordinates[1],
  1151. src: obj.views[0].url,
  1152. desc: obj.tooltip
  1153. };
  1154. },
  1155. URL: ["http://72.167.49.86:8080/KSCam"]
  1156. },
  1157. KY: {
  1158. data(res) {
  1159. return res.features;
  1160. },
  1161. scheme(obj) {
  1162. return {
  1163. state: "KY",
  1164. camType: 5,
  1165. lon: obj.attributes.longitude,
  1166. lat: obj.attributes.latitude,
  1167. src: obj.attributes.snapshot,
  1168. desc: obj.attributes.description
  1169. };
  1170. },
  1171. URL: ['https://services2.arcgis.com/CcI36Pduqd0OR4W9/arcgis/rest/services/trafficCamerasCur_Prd/FeatureServer/0/query?where=id+%3E+0&objectIds=&time=&geometry=&geometryType=esriGeometryPoint&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&returnGeodetic=false&outFields=*&returnGeometry=true&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pjson&token=']
  1172. },
  1173. LA: {
  1174. data(res) {
  1175. return res;
  1176. },
  1177. scheme(obj) {
  1178. if (obj.VideoUrl == null) {
  1179. return {
  1180. state: "LA",
  1181. camType: 1,
  1182. lon: obj.Longitude,
  1183. lat: obj.Latitude,
  1184. src: obj.Url,
  1185. desc: obj.Description,
  1186. width: 480,
  1187. height: 360
  1188. };
  1189. } else {
  1190. return {
  1191. state: "LA",
  1192. camType: 0,
  1193. lon: obj.Longitude,
  1194. lat: obj.Latitude,
  1195. src: obj.VideoUrl,
  1196. desc: obj.Description
  1197. };
  1198. }
  1199. },
  1200. URL: ['http://72.167.49.86:8080/LACam']
  1201. },
  1202. MA: {
  1203. data(res) {
  1204. return res;
  1205. },
  1206. scheme(obj) {
  1207. return {
  1208. state: "MA",
  1209. camType: 1,
  1210. lon: obj.features[0].geometry.coordinates[0],
  1211. lat: obj.features[0].geometry.coordinates[1],
  1212. src: obj.views[0].url,
  1213. desc: obj.tooltip
  1214. };
  1215. },
  1216. URL: ['http://72.167.49.86:8080/MACam']
  1217. },
  1218. MD: {
  1219. data(res) {
  1220. return res.data;
  1221. },
  1222. scheme(obj) {
  1223. return {
  1224. state: "MD",
  1225. camType: 0,
  1226. lon: obj.lon,
  1227. lat: obj.lat,
  1228. src: `https://${obj.cctvIp}/rtplive/${obj.id}/playlist.m3u8`,
  1229. desc: obj.description,
  1230. width: 480,
  1231. height: 360
  1232. };
  1233. },
  1234. URL: ['http://72.167.49.86:8080/MDCam']
  1235. },
  1236. MI: {
  1237. data(res) {
  1238. return res;
  1239. },
  1240. scheme(obj) {
  1241. return {
  1242. state: "MI",
  1243. camType: 1,
  1244. lon: obj.county.match(/(?<=lon=)[\s\S]*(?=&zoom)/)[0],
  1245. lat: obj.county.match(/(?<=lat=)[\s\S]*(?=&lon)/)[0],
  1246. src: obj.image.match(/(?<=src=")[\s\S]*(?=" height=)/)[0],
  1247. desc: `${obj.route} ${obj.location}`
  1248. };
  1249. },
  1250. URL: ['https://mdotjboss.state.mi.us/MiDrive//camera/list']
  1251. },
  1252. MN: {
  1253. data(res) {
  1254. return res;
  1255. },
  1256. scheme(obj) {
  1257. if (obj.streamUrl !== null) {
  1258. return {
  1259. state: "MN",
  1260. camType: 0,
  1261. lon: obj.features[0].geometry.coordinates[0],
  1262. lat: obj.features[0].geometry.coordinates[1],
  1263. src: obj.streamUrl,
  1264. desc: obj.tooltip
  1265. };
  1266. }
  1267. else {
  1268. return {
  1269. state: "MN",
  1270. camType: 1,
  1271. lon: obj.features[0].geometry.coordinates[0],
  1272. lat: obj.features[0].geometry.coordinates[1],
  1273. src: obj.views[0].url,
  1274. desc: obj.tooltip
  1275. };
  1276. }
  1277. },
  1278. URL: ['http://72.167.49.86:8080/MNCam']
  1279. },
  1280. MO: {
  1281. data(res) {
  1282. return res;
  1283. },
  1284. scheme(obj) {
  1285. return {
  1286. state: "MO",
  1287. camType: 0,
  1288. lon: obj.x,
  1289. lat: obj.y,
  1290. src: obj.html,
  1291. desc: obj.location
  1292. };
  1293. },
  1294. URL: ['https://traveler.modot.org/timconfig/feed/desktop/StreamingCams2.json'] // This is disabled until they serve over HTTPS https://traveler.modot.org/timconfig/feed/desktop/StreamingCams2.json
  1295. },
  1296. MS: {
  1297. data(res) {
  1298. return res;
  1299. },
  1300. scheme(obj) {
  1301. return {
  1302. state: "MS",
  1303. camType: 0,
  1304. lon: obj.lon,
  1305. lat: obj.lat,
  1306. src: obj.StreamURL,
  1307. desc: obj.tooltip,
  1308. width: 480,
  1309. height: 360
  1310. };
  1311. },
  1312. URL: ['http://72.167.49.86:8080/MSCam']
  1313. },
  1314. MT: {
  1315. data(res) {
  1316. return res.features;
  1317. },
  1318. scheme(obj) {
  1319. return {
  1320. state: "MT",
  1321. camType: 1,
  1322. lon: obj.geometry.coordinates[0],
  1323. lat: obj.geometry.coordinates[1],
  1324. src: obj.properties.cameras[0].image,
  1325. desc: obj.properties.description
  1326. };
  1327. },
  1328. URL: ['https://mt.cdn.iteris-atis.com/geojson/icons/metadata/icons.cameras.geojson', "https://mt.cdn.iteris-atis.com/geojson/icons/metadata/icons.rwis.geojson"]
  1329. },
  1330. NC: {
  1331. data(res) {
  1332. return res;
  1333. },
  1334. scheme(obj) {
  1335. return {
  1336. state: "NC",
  1337. camType: 4,
  1338. lon: obj.longitude,
  1339. lat: obj.latitude,
  1340. src: obj.id,
  1341. desc: ''
  1342. };
  1343. },
  1344. URL: ['https://eapps.ncdot.gov/services/traffic-prod/v1/cameras/']
  1345. },
  1346. ND: {
  1347. data(res) {
  1348. return res.features;
  1349. },
  1350. scheme(obj) {
  1351. return {
  1352. state: "ND",
  1353. camType: 1,
  1354. lon: obj.geometry.coordinates[0],
  1355. lat: obj.geometry.coordinates[1],
  1356. src: obj.properties.Cameras[0].LinkPath,
  1357. desc: obj.properties.Cameras[0].Description
  1358. };
  1359. },
  1360. URL: ['https://travelfiles.dot.nd.gov/geojson/cameras/1654870342843/cameras.json']
  1361. },
  1362. NE: {
  1363. data(res) {
  1364. return res;
  1365. },
  1366. scheme(obj) {
  1367. return {
  1368. state: "NE",
  1369. camType: 1,
  1370. lon: obj.features[0].geometry.coordinates[0],
  1371. lat: obj.features[0].geometry.coordinates[1],
  1372. src: obj.Url,
  1373. desc: obj.tooltip,
  1374. width: 480,
  1375. height: 360
  1376. };
  1377. },
  1378. URL: ['http://72.167.49.86:8080/NECam']
  1379. },
  1380. NJ: {
  1381. data(res) {
  1382. return res.Data.CameraData;
  1383. },
  1384. scheme(obj) {
  1385. let online, type;
  1386. if (obj.StopCameraFlag == true) { online = false; } else { online = true; }
  1387. if ((obj.CameraMainDetail[0].cameratype == "Video") && (online == true)) { type = 3; } else { type = 1; }
  1388. return {
  1389. state: "NJ",
  1390. enabled: online,
  1391. camType: type,
  1392. lon: obj.longitude,
  1393. lat: obj.latitude,
  1394. src: obj.CameraMainDetail[0].URL,
  1395. desc: obj.name,
  1396. width: 480,
  1397. height: 360
  1398. };
  1399. },
  1400. URL: ['https://publicmap1.511nj.org/api/client/camera/GetCameraDataByTourId?tourid=&rnd=202007201015']
  1401. },
  1402. NM: {
  1403. data(res) {
  1404. return res.cameraInfo;
  1405. },
  1406. scheme(obj) {
  1407. return {
  1408. state: "NM",
  1409. camType: 1,
  1410. lon: obj.lon,
  1411. lat: obj.lat,
  1412. src: "https://servicev4.nmroads.com/RealMapWAR/GetCameraImage?ts=0&cameraName=" + obj.name + "&" + Date.now(),
  1413. desc: obj.title
  1414. };
  1415. },
  1416. URL: ['https://servicev4.nmroads.com/RealMapWAR//GetCameraInfo']
  1417. },
  1418. NV: {
  1419. x(res) {
  1420. return res.ArrayOfCamera.Camera;
  1421. },
  1422. scheme(obj) {
  1423. return {
  1424. state: "NV",
  1425. camType: 0,
  1426. lon: obj.Lon,
  1427. lat: obj.Lat,
  1428. src: obj.StreamingURL.__text,
  1429. desc: obj.Description,
  1430. width: 480,
  1431. height: 360
  1432. };
  1433. },
  1434. URL: ['https://nvroads.com/services/MapServiceProxy.asmx/GetFullCameraList']
  1435. },
  1436. NW: {
  1437. data(res) {
  1438. return res;
  1439. },
  1440. scheme(obj) {
  1441. return {
  1442. state: "NW",
  1443. camType: 1,
  1444. lon: obj.Longitude,
  1445. lat: obj.Latitude,
  1446. src: obj.ImageUrl,
  1447. desc: obj.Name
  1448. };
  1449. },
  1450. URL: ['http://newengland511.org/Traffic/GetCameras']
  1451. },
  1452. NY: {
  1453. data(res) {
  1454. return res;
  1455. },
  1456. scheme(obj) {
  1457. if (obj.VideoUrl == null) {
  1458. return {
  1459. state: "NY",
  1460. camType: 1,
  1461. lon: obj.Longitude,
  1462. lat: obj.Latitude,
  1463. src: obj.Url,
  1464. desc: obj.Name,
  1465. width: 480,
  1466. height: 360
  1467. };
  1468. } else {
  1469. return {
  1470. state: "NY",
  1471. camType: 0,
  1472. lon: obj.Longitude,
  1473. lat: obj.Latitude,
  1474. src: obj.VideoUrl,
  1475. desc: obj.Name
  1476. };
  1477. }
  1478. },
  1479. URL: ['http://72.167.49.86:8080/NYCam']
  1480. },
  1481. OK: {
  1482. data(res) {
  1483. return res;
  1484. },
  1485. scheme(obj) {
  1486. if (obj.mapCameras.length > 0) {
  1487. return {
  1488. state: "OK",
  1489. camType: 0,
  1490. lon: obj.mapCameras[0].longitude,
  1491. lat: obj.mapCameras[0].latitude,
  1492. src: obj.mapCameras[0].streamDictionary.streamSrc,
  1493. desc: obj.name
  1494. };
  1495. }
  1496. },
  1497. URL: ["http://72.167.49.86:8080/OKCam"]
  1498. },
  1499. OH: {
  1500. data(res) {
  1501. return res;
  1502. },
  1503. scheme(obj) {
  1504. return {
  1505. state: "OH",
  1506. camType: 1,
  1507. lon: obj.Longitude,
  1508. lat: obj.Latitude,
  1509. src: obj.Cameras[0].LargeURL,
  1510. desc: obj.Location
  1511. };
  1512. },
  1513. URL: ['https://api.ohgo.com/roadmarkers/cameras']
  1514. },
  1515. OR: {
  1516. data(res) {
  1517. return res.features;
  1518. },
  1519. scheme(obj) {
  1520. return {
  1521. state: "OR",
  1522. camType: 1,
  1523. lon: obj.attributes.longitude,
  1524. lat: obj.attributes.latitude,
  1525. src: `https://tripcheck.com/RoadCams/cams/${obj.attributes.filename}`,
  1526. desc: obj.attributes.title
  1527. };
  1528. },
  1529. URL: ['https://www.tripcheck.com/Scripts/map/data/cctvinventory.js']
  1530. },
  1531. PA: {
  1532. data(res) {
  1533. return res;
  1534. },
  1535. scheme(obj) {
  1536. let online = !obj.videoDisabled;
  1537. if (obj.videoUrl != null) {
  1538. return {
  1539. state: "PA",
  1540. enabled: online,
  1541. camType: 2,
  1542. lon: obj.longitude,
  1543. lat: obj.latitude,
  1544. src: obj.videoUrl,
  1545. id: obj.cameraId,
  1546. desc: obj.displayName,
  1547. subtitle: obj.directionDescriptions
  1548. };
  1549. } else {
  1550. return {
  1551. state: "PA",
  1552. enabled: online,
  1553. camType: 1,
  1554. lon: obj.longitude,
  1555. lat: obj.latitude,
  1556. src: 'https://www.511pa.com/map/Cctv/' + obj.id,
  1557. id: obj.id,
  1558. desc: obj.displayName,
  1559. subtitle: ""
  1560. };
  1561. }
  1562.  
  1563. },
  1564. URL: ['http://72.167.49.86:8080/PACam']
  1565. },
  1566. QC: {
  1567. data(res) {
  1568. return res.features
  1569. },
  1570. scheme(obj) {
  1571. if (obj.properties.titre) {
  1572. return {
  1573. state: "QC",
  1574. camType: 1,
  1575. lon: obj.geometry.coordinates[0],
  1576. lat: obj.geometry.coordinates[1],
  1577. src: obj.properties["url-image-en-direct"],
  1578. desc: obj.properties.titre
  1579. }
  1580. }
  1581. else {
  1582. return {
  1583. state: "QC",
  1584. camType: 5,
  1585. lon: obj.geometry.coordinates[0],
  1586. lat: obj.geometry.coordinates[1],
  1587. src: "https://www.quebec511.info/Carte/Fenetres/FenetreVideo.html?format=mp4&id=" + obj.properties.IDEcamera,
  1588. desc: obj.properties.DescriptionLocalisationFr,
  1589. //subtitle: obj.properties.DescriptionLocalisationEn
  1590. }
  1591. }
  1592. },
  1593. URL: ["https://ville.montreal.qc.ca/circulation/sites/ville.montreal.qc.ca.circulation/files/cameras-de-circulation.json", "https://ws.mapserver.transports.gouv.qc.ca/swtq?service=wfs&version=2.0.0&request=getfeature&typename=ms:infos_cameras&outfile=Camera&srsname=EPSG:4326&outputformat=geojson"]
  1594. },
  1595. RI: {
  1596. data(res) {
  1597. return res.features;
  1598. },
  1599. scheme(obj) {
  1600. return {
  1601. state: "RI",
  1602. camType: 1,
  1603. lon: obj.attributes.Longitude,
  1604. lat: obj.attributes.Latitude,
  1605. src: obj.attributes.CCVEWebURL,
  1606. desc: obj.attributes.Description
  1607. };
  1608. },
  1609. URL: ['https://vueworks.dot.ri.gov/arcgis/rest/services/VW_ITSAssets105/MapServer/2/query?where=OBJECTID+%3E+0&text=&objectIds=&time=&geometry=&geometryType=esriGeometryPoint&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&outFields=*&returnGeometry=true&returnTrueCurves=false&maxAllowableOffset=&geometryPrecision=&outSR=&returnIdsOnly=false&returnCountOnly=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&gdbVersion=&returnDistinctValues=false&resultOffset=&resultRecordCount=&f=pjson']
  1610. },
  1611. SC: {
  1612. data(res) {
  1613. return res.features;
  1614. },
  1615. scheme(obj) {
  1616. return {
  1617. state: "SC",
  1618. camType: 0,
  1619. lon: obj.geometry.coordinates[0],
  1620. lat: obj.geometry.coordinates[1],
  1621. src: obj.properties.https_url,
  1622. desc: obj.properties.description,
  1623. width: 480,
  1624. height: 360
  1625. };
  1626. },
  1627. URL: ['https://sc.cdn.iteris-atis.com/geojson/icons/metadata/icons.cameras.geojson']
  1628. },
  1629. SD: {
  1630. data(res) {
  1631. return res.features;
  1632. },
  1633. scheme(obj) {
  1634. return {
  1635. state: "SD",
  1636. camType: 1,
  1637. lon: obj.geometry.coordinates[0],
  1638. lat: obj.geometry.coordinates[1],
  1639. src: obj.properties.cameras[0].image,
  1640. desc: obj.properties.cameras[0].description,
  1641. width: 480,
  1642. height: 360
  1643. };
  1644. },
  1645. URL: ["https://sd.cdn.iteris-atis.com/geojson/icons/metadata/icons.cameras.geojson"]
  1646. },
  1647. TN: {
  1648. data(res) {
  1649. return res;
  1650. },
  1651. scheme(obj) {
  1652. return {
  1653. state: "TN",
  1654. camType: 0,
  1655. lon: obj.location.coordinates[0].lng,
  1656. lat: obj.location.coordinates[0].lat,
  1657. src: obj.httpsVideoUrl,
  1658. desc: obj.description,
  1659. width: 480,
  1660. height: 360
  1661. };
  1662. },
  1663. URL: ['http://72.167.49.86:8080/TNCam']
  1664. },
  1665. TX: {
  1666. data(res) {
  1667. return res;
  1668. },
  1669. scheme(obj) {
  1670. return {
  1671. state: "TX",
  1672. camType: 6,
  1673. lon: obj.longitude,
  1674. lat: obj.latitude,
  1675. src: [obj.icd_Id, obj.netId],
  1676. desc: obj.name
  1677. };
  1678. },
  1679. URL: ["http://72.167.49.86:8080/TXCam"]
  1680. },
  1681. UT: {
  1682. x(res) {
  1683. return res.kml.Document.Placemark;
  1684. },
  1685. scheme(obj) {
  1686. let coordinates = obj.Point.coordinates.split(",");
  1687. return {
  1688. state: "UT",
  1689. camType: 1,
  1690. lon: coordinates[0],
  1691. lat: coordinates[1],
  1692. src: obj.ExtendedData.SchemaData.SimpleData[6].__text,
  1693. desc: obj.name
  1694. };
  1695. },
  1696. URL: ['https://www.udottraffic.utah.gov/KmlFile.aspx?kmlFileType=Camera']
  1697. },
  1698. VA: {
  1699. data(res) {
  1700. return res.features;
  1701. },
  1702. scheme(obj) {
  1703. return {
  1704. state: "VA",
  1705. camType: 0,
  1706. lon: obj.geometry.coordinates[0],
  1707. lat: obj.geometry.coordinates[1],
  1708. src: obj.properties.https_url,
  1709. desc: obj.properties.description
  1710. };
  1711. },
  1712. URL: ["https://www.511virginia.org/data/geojson/icons.cameras.geojson"]
  1713. },
  1714. WA: {
  1715. data(res) {
  1716. return res;
  1717. },
  1718. scheme(obj) {
  1719. return {
  1720. state: "WA",
  1721. camType: 1,
  1722. lon: obj.CameraLocation.Longitude,
  1723. lat: obj.CameraLocation.Latitude,
  1724. src: obj.ImageURL,
  1725. desc: obj.Title
  1726. };
  1727. },
  1728. URL: ['http://72.167.49.86:8080/WACam']
  1729. },
  1730. WI: {
  1731. data(res) {
  1732. return res;
  1733. },
  1734. scheme(obj) {
  1735. return {
  1736. state: "WI",
  1737. camType: 1,
  1738. lon: obj.Longitude,
  1739. lat: obj.Latitude,
  1740. src: obj.Url,
  1741. desc: obj.Name
  1742. };
  1743. },
  1744. URL: ['http://72.167.49.86:8080/WICam']
  1745. },
  1746. WV: {
  1747. data(res) {
  1748. return res.cams;
  1749. },
  1750. scheme(obj) {
  1751. return {
  1752. state: "WV",
  1753. camType: 0,
  1754. lon: obj.start_lng,
  1755. lat: obj.start_lat,
  1756. src: 'https://sfs1.roadsummary.com/rtplive/' + obj.md5 + '/playlist.m3u8',
  1757. desc: obj.title
  1758. };
  1759. },
  1760. URL: ['http://72.167.49.86:8080/WVCam']
  1761. },
  1762. WY: {
  1763. data(res) {
  1764. return res.features;
  1765. },
  1766. scheme(obj) {
  1767. let LonLat = new OpenLayers.LonLat([obj.geometry.x, obj.geometry.y]).transform('EPSG:3857', 'EPSG:4326');
  1768. return { state: "WY", camType: 5, lon: LonLat.lon, lat: LonLat.lat, src: obj.attributes.IMAGEMARKUP.match(/(?=https:\/\/webcams)[\s\S]*?(?<=\.jpg)/)[0], desc: obj.attributes.IMAGEMARKUP.match(/(?<=<p><i>)[\s\S]*?(?=<\/i><br\/><a href)/)[0] };
  1769. },
  1770. URL: ['https://map.wyoroad.info/wtimap/data/wtimap-webcameras.json']
  1771. }
  1772. };
  1773. })();