jjm2473 / 六只脚KML下载

// ==UserScript==
// @name         六只脚KML下载
// @author       jjm2473
// @copyright    2016, jjm2473@qq.com
// @license      MIT
// @supportURL   mailto:jjm2473@qq.com
// @icon         http://www.foooooot.com/favicon.ico
// @namespace    https://openuserjs.org/users/jjm2473/
// @version      0.4.0
// @description  六只脚轨迹免银两下载,实际是调用json接口获取数据
// @include      /^https?://(www\.)?foooooot\.com/trip/\d+/#?$/
// @include      /^https?://(www\.)?foooooot\.com/map/\??.*$/
// @include      /^https?://6\.lvye\.cn/trip/\d+/#?$/
// @include      /^https?://6\.lvye\.cn/map/\??.*$/
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// ==/UserScript==

/* 
 * 欢迎交流改进
 * @author:jjm2473@qq.com
 **/
function XMLNode(tag){
    this.tagName=tag;
    this.childNodes=[];
    this.innerText=null;
}

XMLNode.prototype = {
    toString:function(indent){
        indent=indent||0;
        var cindent="";
        var i;
        for(i=0;i<indent;++i)cindent+='\t';
        //var nindent=cindent+'\t';
        var result="\n"+cindent+"<"+this.tagName+">";
        if(this.innerText)result+=this.innerText;
        ++indent;
        for(i=0;i<this.childNodes.length;++i){
            result+=this.childNodes[i].toString(indent);
        }
        if(i)result+=("\n"+cindent);
        result+=("</"+this.tagName+">");
        return result;
    },
    appendChild:function(node){
        this.childNodes.push(node);
        return this;
    },
    setText:function(text){
        this.innerText=text;
        return this;
    }
};

(
function(){
    var TIMEZONE = 8*60*60*1000;

    var KMLHeader='<?xml version="1.0" encoding="UTF-8"?>\n'+
                  '<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">';
    var KMLTail='\n</kml>';
    
    var makeTrack = function (name,data){
        var pm=new XMLNode("Placemark");
        pm.appendChild(new XMLNode("name").setText(name))
          .appendChild(new XMLNode("styleUrl").setText("#msn_track"));
        var tr = new XMLNode('gx:Track');
        for(var i=0;i<data.length;++i){
            tr.appendChild(new XMLNode('when').setText(data[i][3]));
            tr.appendChild(new XMLNode('gx:coord').setText(data[i][0]+' '+data[i][1]+' '+data[i][2]));
        }
        pm.appendChild(tr);
        return pm;
    };

    var makePath = function (name,data) {
        var coords=[];
        for(var i=0;i<data.length;++i){
            coords.push(data[i][0]+","+data[i][1]+","+data[i][2]);
        }
        var pm=new XMLNode("Placemark");
        pm.appendChild(new XMLNode("name").setText(name))
          .appendChild(new XMLNode("LineString")
               .appendChild(new XMLNode("coordinates")
                   .setText(coords.join(" "))));
        return pm;
    };
    var getTracksData=function(id, cb){
        var url = "/trip/" + id + "/trackjson/";
        $.getJSON(url, function(data){
            var wpts=[];
            var tz=new Date().getTimezoneOffset()*60*1000;
            $.each(data, function(i, val){
                //wpts.push([val[2],val[1],val[3],new Date(parseInt(val[0])*1000+TIMEZONE).toJSON()]);
                wpts.push([val[2],val[1],val[3],new Date(parseInt(val[0])*1000-tz).toJSON()]);
            });

            cb(wpts);
        });
    };
    var getTracks=function(id, cb){
        getTracksData(id, function(wpts){
            var fl=new XMLNode("Folder");
            fl.appendChild(new XMLNode("name").setText("Tracks"));
            fl.appendChild(makeTrack("Track",wpts))
                .appendChild(makePath("Path",wpts));
            cb(fl);
        });
    };
    var FOOTPRINT_OPT={
        TIME : 0,
		LAT : 1,
		LNG : 2,
		ELEAVTION : 3,
		TITLE : 4,
		THUMBNAIL : 5,
		GALLERY : 6,
		DESCRIPTION : 7,
		TYPE : 8,
		REPLY_TIMES : 9,
		EDIT_URL : 10,
		COMMENT_URL : 11
    };
    var getFootPrint=function(id, cb){
        var url = '/trip/'+id+'/footprintsjson/';
        $.getJSON(url, function(data){
            var fl=new XMLNode("Folder");
            fl.appendChild(new XMLNode("name").setText("Points"));
            $.each(data, function(i, val){
                var pm=new XMLNode("Placemark")
                               .appendChild(new XMLNode("name").setText(val[FOOTPRINT_OPT.TITLE]));
                if(val[FOOTPRINT_OPT.GALLERY]){
                    var desc=new XMLNode("description")
                             .setText('<![CDATA[<img src="'+val[FOOTPRINT_OPT.GALLERY]+'">]]>');
                    pm.appendChild(desc);
                }
                pm.appendChild(new XMLNode("Point")
                               .appendChild(new XMLNode("coordinates")
                                            .setText(val[FOOTPRINT_OPT.LNG]+","+val[FOOTPRINT_OPT.LAT]+","+val[FOOTPRINT_OPT.ELEAVTION])));
                fl.appendChild(pm);
            });
            cb(fl);
        });
    };
    var getMarks=function(id, cb){
        var url = '/trip/'+id+'/marksjson/';
        $.getJSON(url, function(data){
            var fl=new XMLNode("Folder");
            fl.appendChild(new XMLNode("name").setText("Marks"));
            $.each(data, function(i, val){
                var pm=new XMLNode("Placemark")
                               .appendChild(new XMLNode("name").setText(val.title));
                if(val.content){
                    var desc=new XMLNode("description")
                             .setText('<![CDATA[<pre>'+val.content+'</pre>]]>');
                    pm.appendChild(desc);
                }
                pm.appendChild(new XMLNode("Point")
                               .appendChild(new XMLNode("coordinates")
                                            .setText(val.lon+","+val.lat)));
                fl.appendChild(pm);
            });
            cb(fl);
        });
    };
    var getInfo = function(id, cb){
        if(id){
            var url = '/trip/'+id+'/info/';
            $.getJSON(url, function(data){
                var sec = data.duration;
                var hour = parseInt(sec/3600);
                var minute = parseInt(sec%3600/60);

                var str = '于 '+data.occurtime+' 出发,历时 '+hour+' 小时, '+minute+' 分钟\n'+
                data.start_place_name+' - '+data.end_place_name+' | '+data.activity+',全程 '+(parseInt(data.distance*1000)/1000)+' 公里\n'+
                '难度级别:'+data.difficulty+'\n'+
                '累计上升:'+data.accum_uphill+'米, 累计下降:'+data.accum_downhill+'米\n'+
                '海拔最低:'+data.elevation_min+'米, 最高:'+data.elevation_max+'米\n'+
                '最高速度:'+data.speed_max+'公里每小时\n\n'+data.story;
                cb(data.name,str);
            });
        }else{
            cb(document.getElementsByClassName("trip_box_title")[0].children[0].innerText,
            	document.getElementsByClassName('trip_box')[1].innerText);
        }
    };
    var wrapKMLm = function(url,name,info,children){
        var doc=new XMLNode("Document").appendChild(new XMLNode("name").setText(name+".kml"))
               .appendChild(new XMLNode("description").setText('<![CDATA[<a href="'+url+'">'+url+'</a><br/><pre>'+info+'</pre>]]>'))
               .setText('\n\t<atom:author><atom:name>export by jjm2473\'s script</atom:name></atom:author><atom:link href="https://openuserjs.org/scripts/jjm2473/%E5%85%AD%E5%8F%AA%E8%84%9AKML%E4%B8%8B%E8%BD%BD"></atom:link>\n'+
                        '\t<StyleMap id="msn_track"><Pair><key>normal</key><styleUrl>#sn_track</styleUrl></Pair><Pair><key>highlight</key><styleUrl>#sh_track</styleUrl></Pair></StyleMap><Style id="sn_track"><IconStyle><scale>1.2</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/track.png</href></Icon><hotSpot x="32" y="1" xunits="pixels" yunits="pixels"/></IconStyle><ListStyle></ListStyle><LineStyle><color>ffffaa55</color><width>3</width></LineStyle></Style><Style id="sh_track"><IconStyle><scale>1.4</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/track.png</href></Icon><hotSpot x="32" y="32" xunits="pixels" yunits="pixels"/></IconStyle><ListStyle></ListStyle><LineStyle><color>ffffaa55</color><width>3</width></LineStyle></Style>');
        for(var i=0;i<children.length;++i){
            doc.appendChild(children[i]);
        }
        return KMLHeader+doc.toString()+KMLTail;
    };
    var wrapKML = function(id, track,footpoints,marks,name,info){
        return wrapKMLm('http://www.foooooot.com/trip/'+id+'/', name, info, [track,footpoints,marks]);
    };
    var exportString2File = function ( output , filename) {
		var blob = new Blob( [ output ], { type: 'text/plain' } );
		var objectURL = URL.createObjectURL( blob );
        var a=document.createElement('a');
        a.href=objectURL;
        a.download=filename||'Untitled';
        a.click();
	};
    var downloadTrip = function(tripid){
        getTracks(tripid, function(track){
            getFootPrint(tripid, function(footprints){
                getMarks(tripid, function(marks){
                    getInfo(tripid, function(TripName, info){
                    	exportString2File(wrapKML(tripid,track,footprints,marks,TripName,info),tripid+"_"+TripName+".kml");
                	});
                });
            });
        });
        return void(0);
    };
    var onClickListener = function(){
    	var tripid = this.parentNode.id;
        downloadTrip(tripid);
    };
    var createDownloadLink = function(){
    	var aa=document.createElement("a");
    	aa.addEventListener("click",onClickListener);
    	aa.href="javascript:void(0);";
    	//aa.classList.add("inlineIcon");
    	//aa.classList.add("btnDownload");
    	aa.innerHTML='&nbsp;下载KML&nbsp;';
    	return aa;
    };
    
    if(location.pathname.startsWith('/trip/')){
    	//trip view
        console.log('trip view');
    	var tripid=document.getElementById("trip-id");
    	if(tripid === null)return;

    	var div=document.createElement("div");
    	div.id=tripid.value;
    	div.appendChild(createDownloadLink());
    	tripid.parentElement.insertBefore(div,tripid);
    }else if(location.pathname.startsWith('/map/')){
    	//map view
        console.log('map view');
    	/*var listAddLink = function(){
    		var list = document.getElementsByClassName('resultList')[0].getElementsByClassName('tripItem');
    		$.each(list, function(i, val){
    			val.appendChild(createDownloadLink());
    		});
    	};*/
        var funcInject = function(){/*
            if(typeof unsafeWindow.Utils === 'object'){
                unsafeWindow.Utils.successCallbackProxy = function(fn) {
                    return function (result) {
                        var action = result.action;
                        if (!action) {
                            alert("Server Error:ActionNotDefined");
                            throw new Error('Server Error:ActionNotDefined');
                            return ;
                        }
                        var data = action.data;
                        var actionName = action.name;
                        if (actionName == 'redirect') {
                            window.location.href=data.url;
                            return ;
                        }
                        fn && $.isFunction(fn) && fn(actionName,data);
                        listAddLink();
                    };
                };
                listAddLink();
            }else{
                console.error("cannot find var Utils!");
                setTimeout(funcInject,200);
            }
            */
            var tpl = $('.resultList').attr('tpl');
            var idx = tpl.search('</ul>');
            tpl = tpl.substring(0,idx)+'<a href="javascript:void(downloadTrip([[id]]));">&nbsp;下载KML&nbsp;</a>'+tpl.substring(idx);
            /*idx = tpl.search('class="btnShowTrip"');
            tpl = tpl.substring(0,idx)+'onclick="toggleShowTrip([[id]]);"'+tpl.substring(idx);*/
            $('.resultList').attr('tpl', tpl);
        };
        window.downloadTrip = unsafeWindow.downloadTrip = downloadTrip;
        var getSelectTrips = function(){
            var href = window.location.href || unsafeWindow.location.href;
            var selectTrip=[];
            var ts = href.indexOf('|t=');
            if(ts==-1)
                ts = href.indexOf('#t=');
            if(ts==-1)
                return selectTrip;
            ts+=3;
            var te = href.indexOf('|', ts);
            if(ts==te)
                return selectTrip;
            if(te==-1)
                te=href.length;
            var trips = href.substring(ts, te);
            trips = trips.split(',');
            for(var i=0;i<trips.length;++i){
                var tripId = trips[i].substring(0, trips[i].indexOf('*'));
                if(!!tripId)
                    selectTrip.push(tripId);
            }
            return selectTrip;
        };
        /*var selectTrip = [];
        var toggleShowTrip = function(id){
            if(selectTrip.includes(id)){
                selectTrip.pop(id);
            }else{
                selectTrip.push(id);
            }
        };
        window.toggleShowTrip = unsafeWindow.toggleShowTrip = toggleShowTrip;*/
        var downloadSelectedTrip = function(){
            var selectTrip = getSelectTrips();
            var size = selectTrip.length;
            if(size===0)
            {
                alert("未选择任何轨迹!");
                return void(0);
            }
            var href = window.location.href || unsafeWindow.location.href;
            var paths = [];
            var i = 0;
            var looper = function(){
                if(i == size){
                    var fl = new XMLNode("Folder");
                    fl.appendChild(new XMLNode("name").setText("Tracks"));
                    for(i=0;i<size;++i){
                        fl.appendChild(paths[i]);
                    }
                    exportString2File(wrapKMLm(href, selectTrip, '', [fl]), selectTrip+".kml");
                }else{
                    var id=selectTrip[i];
                    ++i;
                    getTracksData(id, function(wpts){
                        paths.push(makePath(id, wpts));
                        setTimeout(looper, 0);
                    });
                }
            };
            looper();
        };
        window.downloadSelectedTrip = unsafeWindow.downloadSelectedTrip = downloadSelectedTrip;
        $('.sortTab').append($('<button style="color:red;margin-left:20px;" onclick="downloadSelectedTrip();">下载选择的轨迹</button>'));
        funcInject();
	}
    console.error("jjm2473,I am here!");//just for debug
})();