Fake GPS Location

Falsify GPS location to protect privacy, or to provide a virtual location sensor device. This script should either be be configured for specific sites only, or for all sites but excludes some specific sites.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Fake GPS Location
// @namespace    https://greasyfork.org/en/users/85671-jcunews
// @version      1.0.1
// @license      AGPLv3
// @author       jcunews
// @description  Falsify GPS location to protect privacy, or to provide a virtual location sensor device. This script should either be be configured for specific sites only, or for all sites but excludes some specific sites.
// @match        *://www.example-mockgps.net/*
// @exclude      *://www.report-real-gps.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(() => {

  //=== CONFIGURATION BEGIN ===

  //Default latitude in decimal degrees (-90 to 90). Negative = South of Equator. Positive = North of Equator.
  var defaultLatitude         = 0;
  //Default longitude in decimal degrees (-180 to 180). Negative = West. Positive = East.
  var defaultLongitude        = 0;
  //Default latitude & longitude accuracy in positive decimal degrees.
  var defaultAccuracy         = 0.000001;

  //Default altitude above sea level in meters.
  var defaultAltitude         = 0;
  //Default altitude accuracy in positive meters. `null` if not available.
  var defaultAltitudeAccuracy = 1;

  //Default heading in degrees. 0 to less than 360. 0 = North, 90 = East, 270 = West, etc. `null` if not available.
  var defaultHeading          = 0;
  //Default speed in meters per second. `null` if not available.
  var defaultSpeed            = 0;

  //Location profiles based on host name of websites.
  //It provides different location information between different websites.
  //All properties for each location profile are optional.
  //If a website host name if not in the list, the default values for all properties will be used.
  //If a property is not specified or has invalid value, the default value will be used.
  //If a property has invalid value range, it will be capped to its value range boundary.
  var locations = {
    "www.example-mockgps.net": {
      latitude: 50.7, longitude: 55, accuracy: 0.1, altitude: 100, altitudeAccuracy: 1, heading: 79.9, speed: 10.5
    },
    "www.another-example-mockgps.net": {
      latitude: -5.1, longitude: 123.4322, accuracy: 0.0002, altitude: 1234.5, altitudeAccuracy: 0.5, heading: 222.2, speed: 1.3
    }
  };

  //Time interval in milliseconds (1000ms is second) to report periodic location report.
  var watchInterval = 1000;

  //=== CONFIGURATION END ===

  Object.keys(locations).forEach(n => {
    n = locations[n];
    if ("number" === typeof n.latitude) {
      if (n.latitude > 90) {
        n.latitude = 90;
      } else if (n.latitude < -90) n.latitude = -90;
    } else n.latitude = defaultLatitude;
    if ("number" === typeof n.longitude) {
      if (n.longitude > 180) {
        n.longitude = 180;
      } else if (n.longitude < -180) n.longitude = -180;
    } else n.longitude = defaultLongitude;
    if ("number" === typeof n.accuracy) {
      if (n.accuracy <= 0) n.accuracy = defaultAccuracy;
    } else if (n.accuracy !== null) n.accuracy = defaultAccuracy;
    if ("number" !== typeof n.altitude) n.altitude = defaultAltitude;
    if ("number" === typeof n.altitudeAccuracy) {
      if (n.altitudeAccuracy <= 0) n.altitudeAccuracy = defaultAltitudeAccuracy;
    } else if (n.altitudeAccuracy !== null) n.altitudeAccuracy = defaultAltitudeAccuracy;
    if ("number" === typeof n.heading) {
      if (n.heading >= 360) {
        n.heading = 359.999999;
      } else if (n.heading < 0) n.heading = 0;
    } else if (n.heading !== null) n.heading = defaultHeading;
    if ("number" === typeof n.speed) {
      if (n.speed < 0) n.speed = 0;
    } else if (n.speed !== null) n.speed = defaultSpeed;
  });

  navigator.geolocation = navigator.geolocation || {};
  navigator.geolocation.getCurrentPosition = function(succ, err) {
    setTimeout((a, b) => {
      if (!(a = locations[location.hostname])) {
        a = {
          latitude: defaultLatitude, longitude: defaultLongitude, accuracy: defaultAccuracy,
          altitude: defaultAltitude, altitudeAccuracy: defaultAltitudeAccuracy, heading: defaultHeading, speed: defaultSpeed
        };
      }
      b = {coords: {}, timestamp: (new Date()).getTime()};
      Object.keys(a).forEach(k => b.coords[k] = a[k]);
      succ(b);
    }, 0);
  };
  navigator.geolocation.watchPosition = function(succ, err) {
    return setInterval((succ, err) => {
      navigator.geolocation.getCurrentPosition(succ, err);
    }, watchInterval, succ, err);
  };
  navigator.geolocation.clearWatch = function(id) {
    clearInterval(id);
  };

})();