```javascript= // ==UserScript== // @name FuckBadDriver-FixTW檢舉交通違規 // @version 0.7 // @description 輸入經緯度,取得中文地址,使用注意事項請見下面註解 // @author Yich // @match https://fixtw.com/cases/new //@run-at document-end // @grant GM_xmlhttpRequest // @namespace https://greasyfork.org/users/175593 // @require https://greasyfork.org/scripts/5392-waitforkeyelements/code/WaitForKeyElements.js?version=115012 // ==/UserScript== /************ 使用注意事項: 1.需要Google的Api key,並enable geocoding api和cloud vision api兩個api 目前是使用我自己申請的api key 2.Chrome安裝Allow CORS: Access-Control-Allow-Origin套件 才能存取上傳的圖片和影片 3.如果要支援不同廠牌的行車紀錄器,或是行車紀錄器影片的時間、坐標格式有更改 可以修改callVision()裡面,呼叫google vision api後的regex判斷 *************/ var Api_Key = ''; (function() { $("#vio_type").after(`<div class='form-group'> <div class='input-group'> <input class='form-control' type='text' id='latlng' style='width:250px' placeholder='經緯度 ex. 25.0800,121.5671'/> <button type='button' class = 'btn-info' id='btnGetAddress' style='margin-left:10px;margin-right:10px'>取得地址</button> <select id="addressList" style='width:400px'></select><br> </div> <div id="progress"></div> </div>`); //點擊取得地址按鈕 $("#btnGetAddress").click(function() { var latlng = $("#latlng").val(); if (latlng) { var address = GetAddress(latlng); if (address.length > 0) { $('#addressList').empty(); $(".illegal-place-input").find("textarea").val(address[0]); $.each(address, function(key, value) { $('#addressList') .append($("<option></option>") .attr("value", value) .text(value)); }); } else { alert("無法取得地址"); } } else { alert("請輸入經緯度"); } }); //選擇地址的下拉選單時,變更textarea的地址 $('#addressList').on('change', function() { $(".illegal-place-input").find("textarea").val(this.value); }); //當上傳影片時,自動取得影片上的文字 waitForKeyElements("span.image_picker_image", tirggerWhenImageUpload); //GetAddress("25.0800,121.5671"); })(); //================= functions ===================================== //輸入坐標,取得地址 function GetAddress(latlng) { //latlng format example: 40.714224,-73.961452 var url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + latlng + '&result_type=street_address|route|premise|intersection|colloquial_area|subpremise' + '&language =zh-TW&key=' + Api_Key var xmlHttp = new XMLHttpRequest(); xmlHttp.open("GET", url, false); // false for synchronous request xmlHttp.send(null); var res = JSON.parse(xmlHttp.responseText); var myRegexp = /(?!\d)(.*)/; var address = $.map(res.results, function(el) { var match = myRegexp.exec(el.formatted_address); var street = match[1].replace("台灣", ""); return street; }); address = $.grep(address, function(v) { return v.length > 6; }); return address; } //截取影片中的圖片 function getVideoImage(blob) { $("#progress").html("<p>開始截取影片中的圖片</p>"); var me = this, video = document.createElement('video'); video.onseeked = function(e) { var canvas = document.createElement('canvas'); canvas.height = video.videoHeight; canvas.width = video.videoWidth; var ctx = canvas.getContext('2d'); ctx.drawImage(video, 0, 0, canvas.width, canvas.height); var img = new Image(); img.src = canvas.toDataURL("image/png"); img.src = img.src.replace(/^data:image\/(png|jpg);base64,/, ""); callVision(img.src); }; video.onerror = function(e) { $("#progress").html("<p>截取影片中的圖片失敗</p>"); }; video.src = blob;//這裡的src用blob物件,而不是用url,防止cors } function loadVideo(videoUrl) { var xhr = new XMLHttpRequest(); xhr.open('get', videoUrl); xhr.responseType = 'blob';//注意,要設置這個請求頭,自己看下面列出的XMLHttpRequest Level 2內容介紹 $("#progress").html("<p>取得影片objectUrl中.. url:"+videoUrl+"<p>"); xhr.onreadystatechange = function () { if (4 == xhr.readyState) { if (200 == xhr.status) { var blob = new Blob([xhr.response], { type: 'video/mp4' }); getVideoImage(URL.createObjectURL(blob)); } else { $("#progress").html('<p>loadVideoFail:'+xhr.status + '\n' + xhr.responseText+'<\p>') } } } xhr.send(null); } // 讀取圖片檔 function getBase64Image(imgUrl) { $("#progress").html("<p>取得base64圖片中.. url:"+imgUrl+"<p>"); var xhr = new XMLHttpRequest(); xhr.onload = function () { var uInt8Array = new Uint8Array(xhr.response); var i = uInt8Array.length; var binaryString = new Array(i); while (i--) { binaryString[i] = String.fromCharCode(uInt8Array[i]); } var data = binaryString.join(''); var b64 = btoa(data); callVision(b64); } xhr.open('GET', imgUrl); xhr.responseType = 'arraybuffer'; xhr.send(); } // Post [Google Cloud Vision API] Request function callVision(Base64_Image) { var request = { "requests": [{ "image": { "content": Base64_Image }, "features": [{ "type": "TEXT_DETECTION", "maxResults": 1 }] }] }; $.ajax({ method: 'POST', url: 'https://vision.googleapis.com/v1/images:annotate?key=' + Api_Key, contentType: 'application/json', data: JSON.stringify(request), processData: false, success: function(data) { var result = data.responses[0].fullTextAnnotation.text; if (result) { //提取出時間和座標 console.log('image OCR result:'+result); var regex = /(\d{4}\/\d{2}\/\d{2}\s+\d{2}:\d{2})/; var match = regex.exec(result); if(match){ var picTime = match[1]; $("#case_illegal_at").val(picTime.replace("/","-"));//將時間格式轉成yyyy-mm-dd hh:mm } var regexlatlng = /E([\d\.]+).*N([\d\.]+)/; var matchlatlng = regexlatlng.exec(result); if(matchlatlng){ var latlng = matchlatlng[2]+','+matchlatlng[1];//matchlatlng[2] = 緯度N matchlatlng[1] = 經度E $("#latlng").val(latlng); $("#btnGetAddress").click(); } $("#progress").html("<p>google OCR辨識成功</p>"); } }, error: function(data, textStatus, errorThrown) { console.log('call google API Error: '); console.log(data); } }) } //當上傳圖片或影片時會觸發 function tirggerWhenImageUpload() { //經緯度和違規地點的input尚未輸入時才會執行 if(!$("#latlng").val()&&!$(".illegal-place-input").find("textarea").val()){ $("#case_image_ids > option").each(function() { var type = $(this).attr("data-source-type"); var src = $(this).attr("data-img-src"); if (type === "video") { $("#progress").html("<p>已上傳檔案 類型:影片</p>"); loadVideo(src); } else if (type === "image") { $("#progress").html("<p>已上傳檔案 類型:圖片</p>"); getBase64Image(src); } }); } } ```