├── LICENSE ├── README.md └── functions ├── DOT_COM_DATA.gs ├── DOUBLE.gs ├── GOOGLEMAPS_DIRECTIONS.gs ├── GOOGLEMAPS_DISTANCE.gs ├── GOOGLEMAPS_DURATION.gs ├── GOOGLEMAPS_LATLONG.gs ├── GOOGLEMAPS_REVERSEGEOCODE.gs ├── GOOGLESUGGEST.gs ├── MD5.gs ├── WIKIARTICLESAROUND.gs ├── WIKICATEGORIES.gs ├── WIKICATEGORYMEMBERS.gs ├── WIKICOMMONSLINK.gs ├── WIKIDATADESCRIPTIONS.gs ├── WIKIDATAFACTS.gs ├── WIKIDATALABELS.gs ├── WIKIDATALOOKUP.gs ├── WIKIDATAQID.gs ├── WIKIDATASEARCH.gs ├── WIKIEXPAND.gs ├── WIKIGEOCOORDINATES.gs ├── WIKIINBOUNDLINKS.gs ├── WIKILINKSEARCH.gs ├── WIKIMUTUALLINKS.gs ├── WIKIOUTBOUNDLINKS.gs ├── WIKIPAGEEDITS.gs ├── WIKIPAGEVIEWS.gs ├── WIKIPAGEVIEWSAGGREGATE.gs ├── WIKIPAGEVIEWSPERARTICLE.gs ├── WIKIPAGEVIEWSTOP.gs ├── WIKIQUARRY.gs ├── WIKISEARCH.gs ├── WIKISUBCATEGORIES.gs ├── WIKISYNONYMS.gs ├── WIKITRANSLATE.gs └── WIKIUNIQUEDEVICES.gs /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Custom Functions 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Custom Functions 2 | 3 | Use [this Google Workspace Add-on](https://workspace.google.com/marketplace/app/custom_functions/3868008326) in Google Sheets to instantly import custom functions, built using Apps Script. 4 | 5 | ![custom-functions-cover](https://user-images.githubusercontent.com/37455462/203621415-22d918d8-d247-4fb2-9dcd-ea771552b6c2.jpeg) 6 | 7 | # Table of contents 8 | - [Installation](#installation) 9 | - [Usage](#usage) 10 | - [Contribute](#contribute) 11 | - [Add new](#add-new) 12 | - [Must have](#must-have) 13 | - [Good to have](#good-to-have) 14 | - [Update existing](#update-existing) 15 | - [License](#license-mit) 16 | 17 | ## Installation 18 | 1. Go to [the add-on page](https://workspace.google.com/marketplace/app/custom_functions/3868008326) 19 | 2. Click on Admin/individual install 20 | 3. Open [sheets.new](https://sheets.new) 21 | 4. Name the sheet (this is so the "Untitled Spreadsheet" gets saved to the Google Drive) 22 | 5. Enable your Google Apps Script API by navigating to [this link](https://script.google.com/home/usersettings) 23 | - Note: In case you have signed-in using multiple Google accounts in the same browser sessions, ensure that you're enabling the API with the same account in which the add-on has been installed 24 | 6. [Optional] Refresh the add-on 25 | 7. Click on any of the function you see from the grid and click to navigate to its page 26 | 8. Click on the IMPORT button 27 | 28 | ### Usage 29 | 30 | Once you've imported a function, those would be as easy to use as a built-in function: 31 | 32 | 1. Click the cell where you want to use the function. 33 | 2. Type an equals sign (`=`) followed by the function name and any input value — for example, `=DOUBLE(A1)` — and press Enter. 34 | 3. The cell will momentarily display `Loading...`, then return the result. 35 | 36 | ## Contribute 37 | 38 | In general, we'll follow the "fork-and-pull" Git workflow: 39 | 40 | 1. Fork this repo on GitHub 41 | 2. Work on your fork 42 | - All the files that you'll need to work with would be in the [functions](/functions/) folder 43 | - Make your additions or changes there 44 | 3. Commit changes to your own branch 45 | 4. Make sure you merge the latest from "upstream" and resolve conflicts (if any) 46 | 5. Push your work back up to your fork 47 | 6. Submit a [Pull request](https://github.com/custom-functions/google-sheets/pulls) so that we can review your changes 48 | 49 | ### Add new 50 | 51 | Use the following as a template when adding a new function — 52 | 53 | ``` 54 | // @author WorkspaceDevs https://developers.google.com/apps-script/guides/sheets/functions#optimization 55 | /** 56 | * Multiplies the input value by 2. 57 | * 58 | * @param {number} input The value or range of cells to multiply. 59 | * @return {number} The input multiplied by 2. 60 | * @customfunction 61 | */ 62 | function DOUBLE(input) { 63 | return Array.isArray(input) ? 64 | input.map(row => row.map(cell => cell * 2)) : 65 | input * 2; 66 | } 67 | ``` 68 | 69 | #### Must have 70 | 71 | 1. JSDoc styled comments 72 | 2. The description of the function needs to go all the way on the top (within JSDoc) 73 | 3. Function needs to have — 74 | - a clear/defined input `@param` (there can be more than 1 of these) 75 | - A single `@return` tag 76 | 4. JSDoc will need to end with the `@customfunction` tag 77 | 5. Ensure to rigorously test the function in your own Apps Script project 78 | 79 | #### Good to have 80 | 81 | 1. Have the `@author` tag added at the very first line of the file (if any) 82 | 2. While the function can return a single value, where possible, it would be good to be able to accomodate `Array` input and return too 83 | 84 | ### Update existing 85 | 86 | Refer the **general** instructions layed out under the [Contribute](#contribute) section. 87 | 88 | ## License (MIT) 89 | 90 | ``` 91 | Copyright (c) 2022 Custom Functions 92 | 93 | Permission is hereby granted, free of charge, to any person obtaining a copy 94 | of this software and associated documentation files (the "Software"), to deal 95 | in the Software without restriction, including without limitation the rights 96 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 97 | copies of the Software, and to permit persons to whom the Software is 98 | furnished to do so, subject to the following conditions: 99 | 100 | The above copyright notice and this permission notice shall be included in all 101 | copies or substantial portions of the Software. 102 | 103 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 104 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 105 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 106 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 107 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 108 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 109 | SOFTWARE. 110 | ``` 111 | -------------------------------------------------------------------------------- /functions/DOT_COM_DATA.gs: -------------------------------------------------------------------------------- 1 | // @author Sourabh Choraria https://script.gs/google-sheets-custom-functions-for-wannabe-domain-investors/ 2 | /** 3 | * Returns data about an available .com domain. 4 | * 5 | * @param {string} name The name of the domain. 6 | * @return {Array} Registrar name, registration & expiration date of a .com domain. 7 | * @customfunction 8 | */ 9 | function DOT_COM_DATA(name) { 10 | const nameComponents = name.replace(/\s+/g, '').split("."); 11 | if (nameComponents.length > 2) return "INVALID INPUT"; 12 | if (nameComponents.length == 2 && nameComponents[1] != "com") return "TLD NOT SUPPORTED"; 13 | name = nameComponents[0]; 14 | const url = `https://rdap.verisign.com/com/v1/domain/${name}.com`; 15 | const response = UrlFetchApp.fetch(url,{ muteHttpExceptions: true }); 16 | if (response.getResponseCode() !== 200) return "AVAILABLE"; 17 | let comData = []; 18 | const jsonData = JSON.parse(response.getContentText()); 19 | const registrar = jsonData.entities[0].vcardArray[1][1][3]; 20 | const registrationDate = jsonData.events[0].eventDate.replace("T"," ").replace("Z",""); 21 | const expirationDate = jsonData.events[1].eventDate.replace("T"," ").replace("Z",""); 22 | comData.push([registrar, registrationDate, expirationDate]); 23 | return comData; 24 | } -------------------------------------------------------------------------------- /functions/DOUBLE.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * Multiplies the input value by 2. 3 | * 4 | * @param {number} input The value or range of cells to multiply. 5 | * @return {number} The input multiplied by 2. 6 | * @customfunction 7 | */ 8 | function DOUBLE(input) { 9 | return Array.isArray(input) ? 10 | input.map(row => row.map(cell => cell * 2)) : 11 | input * 2; 12 | } 13 | -------------------------------------------------------------------------------- /functions/GOOGLEMAPS_DIRECTIONS.gs: -------------------------------------------------------------------------------- 1 | // @author Amit Agarwal https://www.labnol.org/google-maps-sheets-200817 2 | /** 3 | * Find the driving direction between two 4 | * locations on Google Maps. 5 | * 6 | * =GOOGLEMAPS_DIRECTIONS("NY 10005", "Hoboken NJ", "walking") 7 | * 8 | * @param {String} origin The address of starting point 9 | * @param {String} destination The address of destination 10 | * @param {String} mode The mode of travel (driving, walking, bicycling or transit) 11 | * @return {String} The driving direction 12 | * @customFunction 13 | */ 14 | const GOOGLEMAPS_DIRECTIONS = (origin, destination, mode = 'driving') => { 15 | const { routes = [] } = Maps.newDirectionFinder() 16 | .setOrigin(origin) 17 | .setDestination(destination) 18 | .setMode(mode) 19 | .getDirections(); 20 | if (!routes.length) { 21 | throw new Error('No route found!'); 22 | } 23 | return routes 24 | .map(({ legs }) => { 25 | return legs.map(({ steps }) => { 26 | return steps.map((step) => { 27 | return step.html_instructions.replace(/<[^>]+>/g, ''); 28 | }); 29 | }); 30 | }) 31 | .join(', '); 32 | }; -------------------------------------------------------------------------------- /functions/GOOGLEMAPS_DISTANCE.gs: -------------------------------------------------------------------------------- 1 | // @author Amit Agarwal https://www.labnol.org/google-maps-sheets-200817 2 | /** 3 | * Calculate the distance between two 4 | * locations on Google Maps. 5 | * 6 | * =GOOGLEMAPS_DISTANCE("NY 10005", "Hoboken NJ", "walking") 7 | * 8 | * @param {String} origin The address of starting point 9 | * @param {String} destination The address of destination 10 | * @param {String} mode The mode of travel (driving, walking, bicycling or transit) 11 | * @return {String} The distance in miles 12 | * @customfunction 13 | */ 14 | const GOOGLEMAPS_DISTANCE = (origin, destination, mode) => { 15 | const { routes: [data] = [] } = Maps.newDirectionFinder() 16 | .setOrigin(origin) 17 | .setDestination(destination) 18 | .setMode(mode) 19 | .getDirections(); 20 | 21 | if (!data) { 22 | throw new Error('No route found!'); 23 | } 24 | 25 | const { legs: [{ distance: { text: distance } } = {}] = [] } = data; 26 | return distance; 27 | }; 28 | -------------------------------------------------------------------------------- /functions/GOOGLEMAPS_DURATION.gs: -------------------------------------------------------------------------------- 1 | // @author Amit Agarwal https://www.labnol.org/google-maps-sheets-200817 2 | /** 3 | * Calculate the travel time between two locations 4 | * on Google Maps. 5 | * 6 | * =GOOGLEMAPS_DURATION("NY 10005", "Hoboken NJ", "walking") 7 | * 8 | * @param {String} origin The address of starting point 9 | * @param {String} destination The address of destination 10 | * @param {String} mode The mode of travel (driving, walking, bicycling or transit) 11 | * @return {String} The time in minutes 12 | * @customFunction 13 | */ 14 | const GOOGLEMAPS_DURATION = (origin, destination, mode = 'driving') => { 15 | const { routes: [data] = [] } = Maps.newDirectionFinder() 16 | .setOrigin(origin) 17 | .setDestination(destination) 18 | .setMode(mode) 19 | .getDirections(); 20 | if (!data) { 21 | throw new Error('No route found!'); 22 | } 23 | const { legs: [{ duration: { text: time } } = {}] = [] } = data; 24 | return time; 25 | }; -------------------------------------------------------------------------------- /functions/GOOGLEMAPS_LATLONG.gs: -------------------------------------------------------------------------------- 1 | // @author Amit Agarwal https://www.labnol.org/google-maps-sheets-200817 2 | /** 3 | * Get the latitude and longitude of any 4 | * address on Google Maps. 5 | * 6 | * =GOOGLEMAPS_LATLONG("10 Hanover Square, NY") 7 | * 8 | * @param {String} address The address to lookup. 9 | * @return {String} The latitude and longitude of the address. 10 | * @customFunction 11 | */ 12 | const GOOGLEMAPS_LATLONG = (address) => { 13 | const { results: [data = null] = [] } = Maps.newGeocoder().geocode(address); 14 | if (data === null) { 15 | throw new Error('Address not found!'); 16 | } 17 | const { geometry: { location: { lat, lng } } = {} } = data; 18 | return `${lat}, ${lng}`; 19 | }; -------------------------------------------------------------------------------- /functions/GOOGLEMAPS_REVERSEGEOCODE.gs: -------------------------------------------------------------------------------- 1 | // @author Amit Agarwal https://www.labnol.org/google-maps-sheets-200817 2 | /** 3 | * Use Reverse Geocoding to get the address of 4 | * a point location (latitude, longitude) on Google Maps. 5 | * 6 | * =GOOGLEMAPS_REVERSEGEOCODE(latitude, longitude) 7 | * 8 | * @param {String} latitude The latitude to lookup. 9 | * @param {String} longitude The longitude to lookup. 10 | * @return {String} The postal address of the point. 11 | * @customFunction 12 | */ 13 | const GOOGLEMAPS_REVERSEGEOCODE = (latitude, longitude) => { 14 | const { results: [data = {}] = [] } = Maps.newGeocoder().reverseGeocode(latitude, longitude); 15 | return data.formatted_address; 16 | }; -------------------------------------------------------------------------------- /functions/GOOGLESUGGEST.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Google Suggest results for the given keyword. 4 | * 5 | * @param {string} query The query in the format "language:Query" ("de:Berlin") to get suggestions for. 6 | * @return {Array} The list of suggestions. 7 | * @customfunction 8 | */ 9 | function GOOGLESUGGEST(query) { 10 | 'use strict'; 11 | if (!query) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var language; 17 | var title; 18 | if (query.indexOf(':') !== -1) { 19 | language = query.split(/:(.+)?/)[0]; 20 | title = query.split(/:(.+)?/)[1]; 21 | } else { 22 | language = 'en'; 23 | title = query; 24 | } 25 | if (!title) { 26 | return ''; 27 | } 28 | var url = 'https://suggestqueries.google.com/complete/search' + 29 | '?output=toolbar' + 30 | '&hl=' + language + 31 | '&q=' + encodeURIComponent(title); 32 | var xml = UrlFetchApp.fetch(url, { 33 | headers: { 34 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 35 | } 36 | }).getContentText(); 37 | var document = XmlService.parse(xml); 38 | var entries = document.getRootElement().getChildren('CompleteSuggestion'); 39 | for (var i = 0; i < entries.length; i++) { 40 | var text = entries[i].getChild('suggestion').getAttribute('data') 41 | .getValue(); 42 | results[i] = text; 43 | } 44 | } catch (e) { 45 | console.log(JSON.stringify(e)); 46 | } 47 | return results.length > 0 ? results : ''; 48 | } 49 | -------------------------------------------------------------------------------- /functions/MD5.gs: -------------------------------------------------------------------------------- 1 | // @author KEINOS https://gist.github.com/KEINOS/78cc23f37e55e848905fc4224483763d 2 | /** 3 | * Generates an MD5 hash of the input. 4 | * 5 | * @param {string} input The value to be hashed. 6 | * @return {string} The MD5 hash of the input. 7 | * @customfunction 8 | */ 9 | function MD5(input) { 10 | return Array.isArray(input) ? 11 | input.map(row => row.map(cell => helper_(cell))) : 12 | helper_(input); 13 | } 14 | 15 | const helper_ = (input) => { 16 | let output = new String(); 17 | Utilities.computeDigest( 18 | Utilities.DigestAlgorithm.MD5, input) 19 | .forEach(val => { 20 | val < 0 ? val += 256 : null; 21 | val.toString(16).length == 1 ? output += '0' : null; 22 | output += val.toString(16); 23 | }); 24 | return output; 25 | } 26 | -------------------------------------------------------------------------------- /functions/WIKIARTICLESAROUND.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia articles around a Wikipedia article or around a point. 4 | * 5 | * @param {string} articleOrPoint The Wikipedia article in the format "language:Article_Title" ("de:Berlin") or the point in the format "language:Latitude,Longitude" ("en:37.786971,-122.399677") to get articles around for. 6 | * @param {number} radius The search radius in meters. 7 | * @param {boolean=} opt_includeDistance Whether to include the distance in the output, defaults to false (optional). 8 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 9 | * @return {Array} The list of articles around the given article or point. 10 | * @customfunction 11 | */ 12 | function WIKIARTICLESAROUND(articleOrPoint, radius, opt_includeDistance, 13 | opt_namespaces) { 14 | 'use strict'; 15 | if (!articleOrPoint) { 16 | return ''; 17 | } 18 | var results = []; 19 | try { 20 | var language; 21 | var rest; 22 | var title; 23 | var latitude; 24 | var longitude; 25 | if (articleOrPoint.indexOf(':') !== -1) { 26 | language = articleOrPoint.split(/:(.+)?/)[0]; 27 | rest = articleOrPoint.split(/:(.+)?/)[1]; 28 | title = false; 29 | latitude = false; 30 | longitude = false; 31 | if (/^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/.test(rest)) { 32 | latitude = rest.split(',')[0]; 33 | longitude = rest.split(',')[1]; 34 | } else { 35 | title = rest; 36 | } 37 | } else { 38 | language = 'en'; 39 | rest = articleOrPoint; 40 | title = false; 41 | latitude = false; 42 | longitude = false; 43 | if (/^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/.test(rest)) { 44 | latitude = rest.split(',')[0]; 45 | longitude = rest.split(',')[1]; 46 | } else { 47 | title = rest; 48 | } 49 | } 50 | if ((!title) && !(latitude && longitude)) { 51 | return; 52 | } 53 | var url = 'https://' + language + '.wikipedia.org/w/api.php'; 54 | if (title) { 55 | url += '?action=query' + 56 | '&list=geosearch' + 57 | '&format=xml' + 58 | '&gslimit=max' + 59 | '&gsradius=' + radius + 60 | '&gspage=' + encodeURIComponent(title.replace(/\s/g, '_')); 61 | } else { 62 | url += '?action=query' + 63 | '&list=geosearch' + 64 | '&format=xml&gslimit=max' + 65 | '&gsradius=' + radius + 66 | '&gscoord=' + latitude + '%7C' + longitude; 67 | } 68 | url += '&gsnamespace=' + (opt_namespaces ? 69 | encodeURIComponent(opt_namespaces) : '0'); 70 | var xml = UrlFetchApp.fetch(url, { 71 | headers: { 72 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 73 | } 74 | }).getContentText(); 75 | var document = XmlService.parse(xml); 76 | var entries = document.getRootElement().getChild('query') 77 | .getChild('geosearch').getChildren('gs'); 78 | for (var i = 0; i < entries.length; i++) { 79 | var title = entries[i].getAttribute('title').getValue(); 80 | var lat = entries[i].getAttribute('lat').getValue(); 81 | var lon = entries[i].getAttribute('lon').getValue(); 82 | if (opt_includeDistance) { 83 | var dist = entries[i].getAttribute('dist').getValue(); 84 | results[i] = [title, lat, lon, dist]; 85 | } else { 86 | results[i] = [title, lat, lon]; 87 | } 88 | } 89 | } catch (e) { 90 | console.log(JSON.stringify(e)); 91 | } 92 | return results.length > 0 ? results : ''; 93 | } 94 | -------------------------------------------------------------------------------- /functions/WIKICATEGORIES.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia categories for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("en:Berlin") to get categories for. 6 | * @return {Array} The list of categories. 7 | * @customfunction 8 | */ 9 | function WIKICATEGORIES(article) { 10 | 'use strict'; 11 | if (!article) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var language; 17 | var title; 18 | if (article.indexOf(':') !== -1) { 19 | language = article.split(/:(.+)?/)[0]; 20 | title = article.split(/:(.+)?/)[1]; 21 | } else { 22 | language = 'en'; 23 | title = article; 24 | } 25 | if (!title) { 26 | return ''; 27 | } 28 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 29 | '?action=query' + 30 | '&prop=categories' + 31 | '&format=xml' + 32 | '&cllimit=max' + 33 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 34 | var xml = UrlFetchApp.fetch(url, { 35 | headers: { 36 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 37 | } 38 | }).getContentText(); 39 | var document = XmlService.parse(xml); 40 | var entries = document.getRootElement().getChild('query').getChild('pages') 41 | .getChild('page').getChild('categories').getChildren('cl'); 42 | for (var i = 0; i < entries.length; i++) { 43 | var text = entries[i].getAttribute('title').getValue(); 44 | results[i] = text; 45 | } 46 | } catch (e) { 47 | console.log(JSON.stringify(e)); 48 | } 49 | return results.length > 0 ? results : ''; 50 | } 51 | -------------------------------------------------------------------------------- /functions/WIKICATEGORYMEMBERS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia category members for a Wikipedia category. 4 | * 5 | * @param {string} category The Wikipedia category in the format "language:Category_Title" ("en:Category:Visitor_attractions_in_Berlin") to get members for. 6 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 7 | * @return {Array} The list of category members. 8 | * @customfunction 9 | */ 10 | function WIKICATEGORYMEMBERS(category, opt_namespaces) { 11 | 'use strict'; 12 | if (!category) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | var language; 18 | var title; 19 | if ((category.match(/:/g) || []).length > 1) { 20 | language = category.split(/:(.+)?/)[0]; 21 | title = category.split(/:(.+)?/)[1]; 22 | } else { 23 | language = 'en'; 24 | title = category; 25 | } 26 | if (!title) { 27 | return ''; 28 | } 29 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 30 | '?action=query' + 31 | '&list=categorymembers' + 32 | '&cmlimit=max' + 33 | '&cmprop=title' + 34 | '&cmtype=subcat%7Cpage' + 35 | '&format=xml' + 36 | '&cmnamespace=' + (opt_namespaces ? 37 | encodeURIComponent(opt_namespaces) : '0') + 38 | '&cmtitle=' + encodeURIComponent(title.replace(/\s/g, '_')); 39 | var xml = UrlFetchApp.fetch(url, { 40 | headers: { 41 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 42 | } 43 | }).getContentText(); 44 | var document = XmlService.parse(xml); 45 | var entries = document.getRootElement().getChild('query') 46 | .getChild('categorymembers').getChildren('cm'); 47 | for (var i = 0; i < entries.length; i++) { 48 | var text = entries[i].getAttribute('title').getValue(); 49 | results[i] = text; 50 | } 51 | } catch (e) { 52 | console.log(JSON.stringify(e)); 53 | } 54 | return results.length > 0 ? results : ''; 55 | } 56 | -------------------------------------------------------------------------------- /functions/WIKICOMMONSLINK.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the Wikimedia Commons link for a file. 4 | * 5 | * @param {string} fileName The Wikimedia Commons file name in the format "language:File_Name" ("en:Flag of Berlin.svg") to get the link for. 6 | * @return {string} The link of the Wikimedia Commons file. 7 | * @customfunction 8 | */ 9 | function WIKICOMMONSLINK(fileName) { 10 | 'use strict'; 11 | if (!fileName) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var language; 17 | var title; 18 | if (fileName.indexOf(':') !== -1) { 19 | language = fileName.split(/:(.+)?/)[0]; 20 | title = fileName.split(/:(.+)?/)[1]; 21 | } else { 22 | language = 'en'; 23 | title = fileName; 24 | } 25 | if (!title) { 26 | return ''; 27 | } 28 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 29 | '?action=query' + 30 | '&prop=imageinfo' + 31 | '&iiprop=url' + 32 | '&format=xml' + 33 | '&titles=File:' + encodeURIComponent(title.replace(/\s/g, '_')); 34 | var xml = UrlFetchApp.fetch(url, { 35 | headers: { 36 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 37 | } 38 | }).getContentText(); 39 | var document = XmlService.parse(xml); 40 | var entry = document.getRootElement().getChild('query').getChild('pages') 41 | .getChild('page').getChild('imageinfo').getChild('ii'); 42 | var fileUrl = entry.getAttribute('url').getValue(); 43 | results[0] = fileUrl; 44 | } catch (e) { 45 | console.log(JSON.stringify(e)); 46 | } 47 | return results.length > 0 ? results : ''; 48 | } -------------------------------------------------------------------------------- /functions/WIKIDATADESCRIPTIONS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the descriptions for a Wikidata item. 4 | * 5 | * @param {string} qid The Wikidata item's qid to get the label for. 6 | * @param {Array=} opt_targetLanguages The list of languages to limit the results to, or "all" (optional). 7 | * @return {Array} The label. 8 | * @customfunction 9 | */ 10 | function WIKIDATADESCRIPTIONS(qid, opt_targetLanguages) { 11 | 'use strict'; 12 | if (!qid) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | opt_targetLanguages = opt_targetLanguages || []; 18 | opt_targetLanguages = Array.isArray(opt_targetLanguages) ? 19 | opt_targetLanguages : [opt_targetLanguages]; 20 | if (opt_targetLanguages.length === 0) { 21 | opt_targetLanguages = ['en']; 22 | } 23 | if (opt_targetLanguages.length === 1 && opt_targetLanguages[0] === 'all') { 24 | opt_targetLanguages = []; 25 | } 26 | var url = 'https://www.wikidata.org/w/api.php' + 27 | '?format=json' + 28 | '&action=wbgetentities' + 29 | '&props=descriptions' + 30 | '&ids=' + qid + 31 | (opt_targetLanguages.length ? 32 | '&languages=' + opt_targetLanguages.join('%7C') : ''); 33 | var json = JSON.parse(UrlFetchApp.fetch(url, { 34 | headers: { 35 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 36 | } 37 | }).getContentText()); 38 | var descriptions = json.entities[qid].descriptions; 39 | var availableLanguages = Object.keys(descriptions).sort(); 40 | availableLanguages.forEach(function (language) { 41 | var description = descriptions[language].value; 42 | results.push([language, description]); 43 | }); 44 | } catch (e) { 45 | console.log(JSON.stringify(e)); 46 | } 47 | return results.length > 0 ? results : ''; 48 | } 49 | -------------------------------------------------------------------------------- /functions/WIKIDATAFACTS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikidata facts for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") or the Wikidata entity in the format "qid" ("Q42") to get Wikidata facts for. 6 | * @param {string=} opt_multiObjectMode Whether to return all object values (pass "all") or just the first (pass "first") when there are more than one object values (optional). 7 | * @param {Array} opt_properties Limit the resulting facts to a list of properties (optional). 8 | * @return {Array} The list of Wikidata facts. 9 | * @customfunction 10 | */ 11 | function WIKIDATAFACTS(article, opt_multiObjectMode, opt_properties) { 12 | 'use strict'; 13 | 14 | var simplifyClaims = function (claims) { 15 | var simpleClaims = {}; 16 | for (var id in claims) { 17 | var claim = claims[id]; 18 | simpleClaims[id] = simpifyClaim(claim); 19 | } 20 | return simpleClaims; 21 | }; 22 | 23 | var simpifyClaim = function (claim) { 24 | var simplifiedClaim = []; 25 | var len = claim.length; 26 | for (var i = 0; i < len; i++) { 27 | var statement = claim[i]; 28 | var simpifiedStatement = simpifyStatement(statement); 29 | if (simpifiedStatement !== null) { 30 | simplifiedClaim.push(simpifiedStatement); 31 | } 32 | } 33 | return simplifiedClaim; 34 | }; 35 | 36 | var simpifyStatement = function (statement) { 37 | var mainsnak = statement.mainsnak; 38 | if (mainsnak === null) { 39 | return null; 40 | } 41 | var datatype = mainsnak.datatype; 42 | var datavalue = mainsnak.datavalue; 43 | if (datavalue === null || datavalue === undefined) { 44 | return null; 45 | } 46 | switch (datatype) { 47 | case 'string': 48 | case 'commonsMedia': 49 | case 'url': 50 | case 'math': 51 | case 'external-id': 52 | return datavalue.value; 53 | case 'monolingualtext': 54 | return datavalue.value.text; 55 | case 'wikibase-item': 56 | var qid = 'Q' + datavalue.value['numeric-id']; 57 | qids.push(qid); 58 | return qid; 59 | case 'time': 60 | return datavalue.value.time; 61 | case 'quantity': 62 | return datavalue.value.amount; 63 | default: 64 | return null; 65 | } 66 | }; 67 | 68 | var getPropertyAndEntityLabels = function (propertiesAndEntities) { 69 | var labels = {}; 70 | try { 71 | var size = 50; 72 | var j = propertiesAndEntities.length; 73 | for (var i = 0; i < j; i += size) { 74 | var chunk = propertiesAndEntities.slice(i, i + size); 75 | var url = 'https://www.wikidata.org/w/api.php' + 76 | '?action=wbgetentities' + 77 | '&languages=en' + 78 | '&format=json' + 79 | '&props=labels' + 80 | '&ids=' + chunk.join('%7C'); 81 | var json = JSON.parse(UrlFetchApp.fetch(url, { 82 | headers: { 83 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 84 | } 85 | }).getContentText()); 86 | var entities = json.entities; 87 | chunk.forEach(function (item) { 88 | if ((entities[item]) && 89 | (entities[item].labels) && 90 | (entities[item].labels.en) && 91 | (entities[item].labels.en.value)) { 92 | labels[item] = entities[item].labels.en.value; 93 | } else { 94 | labels[item] = false; 95 | } 96 | }); 97 | } 98 | } catch (e) { 99 | console.log(JSON.stringify(e)); 100 | } 101 | return labels; 102 | }; 103 | 104 | if (!article) { 105 | return ''; 106 | } 107 | opt_properties = opt_properties || []; 108 | opt_properties = Array.isArray(opt_properties) ? 109 | opt_properties : [opt_properties]; 110 | var temp = {}; 111 | opt_properties.forEach(function (prop) { 112 | temp[prop] = true; 113 | }); 114 | opt_properties = Object.keys(temp); 115 | var results = []; 116 | try { 117 | var language; 118 | var title; 119 | if (article.indexOf(':') !== -1) { 120 | language = article.split(/:(.+)?/)[0]; 121 | title = article.split(/:(.+)?/)[1]; 122 | } else { 123 | language = 'en'; 124 | title = article; 125 | } 126 | if (!title) { 127 | return ''; 128 | } 129 | var url; 130 | if (/^Q\d+$/.test(title)) { 131 | url = 'https://www.wikidata.org/w/api.php' + 132 | '?action=wbgetentities' + 133 | '&format=json' + 134 | '&props=claims' + 135 | '&ids=' + title; 136 | } else { 137 | url = 'https://wikidata.org/w/api.php' + 138 | '?action=wbgetentities' + 139 | '&sites=' + language + 'wiki' + 140 | '&format=json' + 141 | '&props=claims' + 142 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 143 | } 144 | var json = JSON.parse(UrlFetchApp.fetch(url, { 145 | headers: { 146 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 147 | } 148 | }).getContentText()); 149 | var entity = Object.keys(json.entities)[0]; 150 | var qids = []; 151 | var simplifiedClaims = simplifyClaims(json.entities[entity].claims); 152 | var properties = Object.keys(simplifiedClaims); 153 | if (opt_properties.length) { 154 | properties = properties.filter(function (property) { 155 | return opt_properties.indexOf(property) !== -1; 156 | }); 157 | } 158 | var labels = getPropertyAndEntityLabels(properties.concat(qids)); 159 | for (var claim in simplifiedClaims) { 160 | var claims = simplifiedClaims[claim].filter(function (value) { 161 | return value !== null; 162 | }); 163 | // Only return single-object facts 164 | if (claims.length === 1) { 165 | var label = labels[claim]; 166 | var value = /^Q\d+$/.test(claims[0]) ? labels[claims[0]] : claims[0]; 167 | if (label && value) { 168 | results.push([label, value]); 169 | } 170 | } 171 | // Optionally return multi-object facts 172 | if (( 173 | (/^first$/i.test(opt_multiObjectMode)) || 174 | (/^all$/i.test(opt_multiObjectMode)) 175 | ) && (claims.length > 1)) { 176 | var label = labels[claim]; 177 | claims.forEach(function (claimObject, i) { 178 | if (i > 0 && /^first$/i.test(opt_multiObjectMode)) { 179 | return; 180 | } 181 | var value = /^Q\d+$/.test(claimObject) ? 182 | labels[claimObject] : claimObject; 183 | if (label && value) { 184 | results.push([label, value]); 185 | } 186 | }); 187 | } 188 | } 189 | } catch (e) { 190 | console.log(JSON.stringify(e)); 191 | } 192 | return results.length > 0 ? results : ''; 193 | } 194 | -------------------------------------------------------------------------------- /functions/WIKIDATALABELS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the labels for a Wikidata item. 4 | * 5 | * @param {string} qid The Wikidata item's qid to get the labels for. 6 | * @param {Array=} opt_targetLanguages The list of languages to limit the results to, or "all" (optional). 7 | * @return {Array} The labels. 8 | * @customfunction 9 | */ 10 | function WIKIDATALABELS(qid, opt_targetLanguages) { 11 | 'use strict'; 12 | if (!qid) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | opt_targetLanguages = opt_targetLanguages || []; 18 | opt_targetLanguages = Array.isArray(opt_targetLanguages) ? 19 | opt_targetLanguages : [opt_targetLanguages]; 20 | if (opt_targetLanguages.length === 0) { 21 | opt_targetLanguages = ['en']; 22 | } 23 | if (opt_targetLanguages.length === 1 && opt_targetLanguages[0] === 'all') { 24 | opt_targetLanguages = []; 25 | } 26 | var url = 'https://www.wikidata.org/w/api.php' + 27 | '?format=json' + 28 | '&action=wbgetentities' + 29 | '&props=labels' + 30 | '&ids=' + qid + 31 | (opt_targetLanguages.length ? 32 | '&languages=' + opt_targetLanguages.join('%7C') : ''); 33 | var json = JSON.parse(UrlFetchApp.fetch(url, { 34 | headers: { 35 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 36 | } 37 | }).getContentText()); 38 | var labels = json.entities[qid].labels; 39 | var availableLanguages = Object.keys(labels).sort(); 40 | availableLanguages.forEach(function (language) { 41 | var label = labels[language].value; 42 | results.push([language, label]); 43 | }); 44 | } catch (e) { 45 | console.log(JSON.stringify(e)); 46 | } 47 | return results.length > 0 ? results : ''; 48 | } 49 | -------------------------------------------------------------------------------- /functions/WIKIDATALOOKUP.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the Wikidata qid of the given identifier and property. 4 | * 5 | * Internally, this function invokes a haswbstatement query against the Wikidata API. 6 | * 7 | * @param {string} property The Wikidata property (such as "P298"). 8 | * @param {string} identifier The identifier (value) to lookup (such as "AUT"). 9 | * @return {string} The Wikidata qid. 10 | * @customfunction 11 | */ 12 | function WIKIDATALOOKUP(property, identifier) { 13 | 'use strict'; 14 | var results = []; 15 | try { 16 | var url = 'https://www.wikidata.org/w/api.php' + 17 | '?action=query' + 18 | '&format=json' + 19 | '&formatversion=2' + 20 | '&list=search' + 21 | '&ppprop=wikibase_item' + 22 | '&srsearch=haswbstatement:' + property + '=' + encodeURIComponent(identifier); 23 | var json = JSON.parse(UrlFetchApp.fetch(url, { 24 | headers: { 25 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 26 | } 27 | }).getContentText()); 28 | results[0] = json.query.search[0].title; 29 | } catch (e) { 30 | console.log(JSON.stringify(e)); 31 | } 32 | return results.length > 0 ? results : ''; 33 | } 34 | -------------------------------------------------------------------------------- /functions/WIKIDATAQID.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the Wikidata qid of the corresponding Wikidata item for a Wikipedia article. 4 | * 5 | * @param {string} article The article in the format "language:Query" ("de:Berlin") to get the Wikidata qid for. 6 | * @return {string} The Wikidata qid. 7 | * @customfunction 8 | */ 9 | function WIKIDATAQID(article) { 10 | 'use strict'; 11 | if (!article) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var language; 17 | var title; 18 | if (article.indexOf(':') !== -1) { 19 | language = article.split(/:(.+)?/)[0]; 20 | title = article.split(/:(.+)?/)[1]; 21 | } else { 22 | language = 'en'; 23 | title = article; 24 | } 25 | if (!title) { 26 | return ''; 27 | } 28 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 29 | '?action=query' + 30 | '&format=json' + 31 | '&formatversion=2' + 32 | '&redirects=1' + 33 | '&prop=pageprops' + 34 | '&ppprop=wikibase_item' + 35 | '&titles=' + encodeURIComponent(title); 36 | var json = JSON.parse(UrlFetchApp.fetch(url, { 37 | headers: { 38 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 39 | } 40 | }).getContentText()); 41 | if (json.query.pages[0] && json.query.pages[0].pageprops.wikibase_item) { 42 | results[0] = json.query.pages[0].pageprops.wikibase_item; 43 | } 44 | } catch (e) { 45 | console.log(JSON.stringify(e)); 46 | } 47 | return results.length > 0 ? results : ''; 48 | } 49 | -------------------------------------------------------------------------------- /functions/WIKIDATASEARCH.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Searches for Wikidata entities using Wikidata labels and aliases. 4 | * 5 | * @param {string} search The search string in the format "language:Query" ("de:Berlin") to get the Wikidata qid for. 6 | * @return {string} The Wikidata qid. 7 | * @customfunction 8 | */ 9 | function WIKIDATASEARCH(search) { 10 | 'use strict'; 11 | if (!search) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var wbslanguage; 17 | var wbssearch; 18 | if (search.indexOf(':') !== -1) { 19 | wbslanguage = search.split(/:(.+)?/)[0]; 20 | wbssearch = search.split(/:(.+)?/)[1]; 21 | } else { 22 | wbslanguage = 'en'; 23 | wbssearch = search; 24 | } 25 | if (!wbssearch) { 26 | return ''; 27 | } 28 | var url = 'https://www.wikidata.org/w/api.php' + 29 | '?action=query' + 30 | '&list=wbsearch' + 31 | '&wbslanguage=' + wbslanguage + 32 | '&format=json' + 33 | '&wbssearch=' + encodeURIComponent(wbssearch); 34 | var json = JSON.parse(UrlFetchApp.fetch(url, { 35 | headers: { 36 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 37 | } 38 | }).getContentText()); 39 | results[0] = json.query.wbsearch[0].title; 40 | } catch (e) { 41 | console.log(JSON.stringify(e)); 42 | } 43 | return results.length > 0 ? results : ''; 44 | } 45 | -------------------------------------------------------------------------------- /functions/WIKIEXPAND.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia translations (language links) and synonyms (redirects) for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get translations and synonyms for. 6 | * @param {Array=} opt_targetLanguages The list of languages to limit the results to (optional). 7 | * @return {Array} The list of translations and synonyms. 8 | * @customfunction 9 | */ 10 | function WIKIEXPAND(article, opt_targetLanguages) { 11 | 'use strict'; 12 | if (!article) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | var language; 18 | var title; 19 | if (article.indexOf(':') !== -1) { 20 | language = article.split(/:(.+)?/)[0]; 21 | title = article.split(/:(.+)?/)[1]; 22 | } else { 23 | language = 'en'; 24 | title = article; 25 | } 26 | if (!title) { 27 | return ''; 28 | } 29 | opt_targetLanguages = opt_targetLanguages || []; 30 | opt_targetLanguages = Array.isArray(opt_targetLanguages) ? 31 | opt_targetLanguages : [opt_targetLanguages]; 32 | var temp = {}; 33 | opt_targetLanguages.forEach(function (lang) { 34 | temp[lang] = true; 35 | }); 36 | opt_targetLanguages = Object.keys(temp); 37 | var translations = WIKITRANSLATE_(article, opt_targetLanguages, false, true); 38 | var i = 0; 39 | for (var lang in translations) { 40 | var synonyms = WIKISYNONYMS_(lang + ':' + translations[lang]); 41 | results[i] = [lang].concat(([translations[lang]].concat(synonyms))); 42 | i++; 43 | } 44 | } catch (e) { 45 | console.log(JSON.stringify(e)); 46 | } 47 | return results; 48 | } 49 | 50 | function WIKITRANSLATE_(article, opt_targetLanguages, opt_skipHeader, 51 | _opt_returnAsObject) { 52 | 'use strict'; 53 | if (!article) { 54 | return ''; 55 | } 56 | var results = {}; 57 | opt_targetLanguages = opt_targetLanguages || []; 58 | opt_targetLanguages = Array.isArray(opt_targetLanguages) ? 59 | opt_targetLanguages : [opt_targetLanguages]; 60 | var temp = {}; 61 | opt_targetLanguages.forEach(function(lang) { 62 | temp[lang] = true; 63 | }); 64 | opt_targetLanguages = Object.keys(temp); 65 | try { 66 | var language; 67 | var title; 68 | if (article.indexOf(':') !== -1) { 69 | language = article.split(/:(.+)?/)[0]; 70 | title = article.split(/:(.+)?/)[1]; 71 | } else { 72 | language = 'en'; 73 | title = article; 74 | } 75 | if (!title) { 76 | return ''; 77 | } 78 | opt_targetLanguages.forEach(function(targetLanguage) { 79 | if (targetLanguage) { 80 | results[targetLanguage] = title.replace(/_/g, ' '); 81 | } 82 | }); 83 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 84 | '?action=query' + 85 | '&prop=langlinks' + 86 | '&format=xml' + 87 | '&lllimit=max' + 88 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 89 | var xml = UrlFetchApp.fetch(url, { 90 | headers: { 91 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 92 | } 93 | }).getContentText(); 94 | var document = XmlService.parse(xml); 95 | var entries = document.getRootElement().getChild('query').getChild('pages') 96 | .getChild('page').getChild('langlinks').getChildren('ll'); 97 | var targetLanguagesSet = opt_targetLanguages.length > 0; 98 | for (var i = 0; i < entries.length; i++) { 99 | var text = entries[i].getText(); 100 | var lang = entries[i].getAttribute('lang').getValue(); 101 | if ((targetLanguagesSet) && (opt_targetLanguages.indexOf(lang) === -1)) { 102 | continue; 103 | } 104 | results[lang] = text; 105 | } 106 | title = title.replace(/_/g, ' '); 107 | results[language] = title; 108 | } catch (e) { 109 | // no-op 110 | } 111 | if (_opt_returnAsObject) { 112 | return results; 113 | } 114 | var arrayResults = []; 115 | for (var lang in results) { 116 | if (opt_skipHeader) { 117 | arrayResults.push(results[lang]); 118 | } else { 119 | arrayResults.push([lang, results[lang]]); 120 | } 121 | } 122 | return arrayResults.length > 0 ? arrayResults : ''; 123 | } 124 | 125 | function WIKISYNONYMS_(article, opt_namespaces) { 126 | 'use strict'; 127 | if (!article) { 128 | return ''; 129 | } 130 | var results = []; 131 | try { 132 | var language; 133 | var title; 134 | if (article.indexOf(':') !== -1) { 135 | language = article.split(/:(.+)?/)[0]; 136 | title = article.split(/:(.+)?/)[1]; 137 | } else { 138 | language = 'en'; 139 | title = article; 140 | } 141 | if (!title) { 142 | return ''; 143 | } 144 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 145 | '?action=query' + 146 | '&blnamespace=' + (opt_namespaces ? 147 | encodeURIComponent(opt_namespaces) : '0') + 148 | '&list=backlinks' + 149 | '&blfilterredir=redirects' + 150 | '&bllimit=max' + 151 | '&format=xml' + 152 | '&bltitle=' + encodeURIComponent(title.replace(/\s/g, '_')); 153 | var xml = UrlFetchApp.fetch(url, { 154 | headers: { 155 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 156 | } 157 | }).getContentText(); 158 | var document = XmlService.parse(xml); 159 | var entries = document.getRootElement().getChild('query') 160 | .getChild('backlinks').getChildren('bl'); 161 | for (var i = 0; i < entries.length; i++) { 162 | var text = entries[i].getAttribute('title').getValue(); 163 | results[i] = text; 164 | } 165 | } catch (e) { 166 | // no-op 167 | } 168 | return results.length > 0 ? results : ''; 169 | } 170 | -------------------------------------------------------------------------------- /functions/WIKIGEOCOORDINATES.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia geocoordinates for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get geocoordinates for. 6 | * @return {Array} The latitude and longitude. 7 | * @customfunction 8 | */ 9 | function WIKIGEOCOORDINATES(article) { 10 | 'use strict'; 11 | if (!article) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var language; 17 | var title; 18 | if (article.indexOf(':') !== -1) { 19 | language = article.split(/:(.+)?/)[0]; 20 | title = article.split(/:(.+)?/)[1]; 21 | } else { 22 | language = 'en'; 23 | title = article; 24 | } 25 | if (!title) { 26 | return ''; 27 | } 28 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 29 | '?action=query' + 30 | '&prop=coordinates' + 31 | '&format=xml' + 32 | '&colimit=max' + 33 | '&coprimary=primary' + 34 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 35 | var xml = UrlFetchApp.fetch(url, { 36 | headers: { 37 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 38 | } 39 | }).getContentText(); 40 | var document = XmlService.parse(xml); 41 | var coordinates = document.getRootElement().getChild('query') 42 | .getChild('pages').getChild('page').getChild('coordinates') 43 | .getChild('co'); 44 | var latitude = coordinates.getAttribute('lat').getValue(); 45 | var longitude = coordinates.getAttribute('lon').getValue(); 46 | results = [[latitude, longitude]]; 47 | } catch (e) { 48 | console.log(JSON.stringify(e)); 49 | } 50 | return results.length > 0 ? results : ''; 51 | } 52 | -------------------------------------------------------------------------------- /functions/WIKIINBOUNDLINKS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia inbound links for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get inbound links for. 6 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 7 | * @return {Array} The list of inbound links. 8 | * @customfunction 9 | */ 10 | function WIKIINBOUNDLINKS(article, opt_namespaces) { 11 | 'use strict'; 12 | if (!article) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | var language; 18 | var title; 19 | if (article.indexOf(':') !== -1) { 20 | language = article.split(/:(.+)?/)[0]; 21 | title = article.split(/:(.+)?/)[1]; 22 | } else { 23 | language = 'en'; 24 | title = article; 25 | } 26 | if (!title) { 27 | return ''; 28 | } 29 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 30 | '?action=query' + 31 | '&list=backlinks' + 32 | '&bllimit=max' + 33 | '&blnamespace=' + (opt_namespaces ? 34 | encodeURIComponent(opt_namespaces) : '0') + 35 | '&format=xml' + 36 | '&bltitle=' + encodeURIComponent(title.replace(/\s/g, '_')); 37 | var xml = UrlFetchApp.fetch(url, { 38 | headers: { 39 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 40 | } 41 | }).getContentText(); 42 | var document = XmlService.parse(xml); 43 | var entries = document.getRootElement().getChild('query') 44 | .getChild('backlinks').getChildren('bl'); 45 | for (var i = 0; i < entries.length; i++) { 46 | var text = entries[i].getAttribute('title').getValue(); 47 | results[i] = text; 48 | } 49 | } catch (e) { 50 | console.log(JSON.stringify(e)); 51 | } 52 | return results.length > 0 ? results : ''; 53 | } 54 | -------------------------------------------------------------------------------- /functions/WIKILINKSEARCH.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia articles that have a link that matches a given link pattern. 4 | * 5 | * @param {string} linkPattern The link pattern to search for in the format "language:example.com" or "language:*.example.com". 6 | * @param {string=} opt_protocol Protocol of the link, defaults to "http" (optional). 7 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 8 | * @return {Array} The list of articles that match the link pattern and the concrete link. 9 | * @customfunction 10 | */ 11 | function WIKILINKSEARCH(linkPattern, opt_protocol, opt_namespaces) { 12 | 'use strict'; 13 | if (!linkPattern) { 14 | return ''; 15 | } 16 | var results = []; 17 | try { 18 | var language; 19 | var title; 20 | if (linkPattern.indexOf(':') !== -1) { 21 | language = linkPattern.split(/:(.+)?/)[0]; 22 | title = linkPattern.split(/:(.+)?/)[1]; 23 | } else { 24 | language = 'en'; 25 | title = linkPattern; 26 | } 27 | if (!title) { 28 | return ''; 29 | } 30 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 31 | '?action=query' + 32 | '&format=xml' + 33 | '&list=exturlusage' + 34 | '&eulimit=max' + 35 | '&euprop=title%7Curl' + 36 | '&euprotocol=' + (opt_protocol ? opt_protocol : 'http') + 37 | '&euquery=' + encodeURIComponent(title) + 38 | '&eunamespace=' + (opt_namespaces ? 39 | encodeURIComponent(opt_namespaces) : '0'); 40 | var xml = UrlFetchApp.fetch(url, { 41 | headers: { 42 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 43 | } 44 | }).getContentText(); 45 | var document = XmlService.parse(xml); 46 | var entries = document.getRootElement().getChild('query') 47 | .getChild('exturlusage').getChildren('eu'); 48 | for (var i = 0; i < entries.length; i++) { 49 | var title = entries[i].getAttribute('title').getValue(); 50 | var url = entries[i].getAttribute('url').getValue(); 51 | results[i] = [title, url]; 52 | } 53 | } catch (e) { 54 | console.log(JSON.stringify(e)); 55 | } 56 | return results.length > 0 ? results : ''; 57 | } 58 | -------------------------------------------------------------------------------- /functions/WIKIMUTUALLINKS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia mutual links, i.e, the intersection of inbound and outbound links for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get mutual links for. 6 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 7 | * @return {Array} The list of mutual links. 8 | * @customfunction 9 | */ 10 | function WIKIMUTUALLINKS(article, opt_namespaces) { 11 | 'use strict'; 12 | var inboundLinks = WIKIINBOUNDLINKS_(article, opt_namespaces); 13 | var outboundLinks = WIKIOUTBOUNDLINKS_(article, opt_namespaces); 14 | var mutualLinks = inboundLinks.filter(function (link) { 15 | return outboundLinks.indexOf(link) > -1; 16 | }); 17 | return mutualLinks; 18 | } 19 | 20 | function WIKIINBOUNDLINKS_(article, opt_namespaces) { 21 | 'use strict'; 22 | if (!article) { 23 | return ''; 24 | } 25 | var results = []; 26 | try { 27 | var language; 28 | var title; 29 | if (article.indexOf(':') !== -1) { 30 | language = article.split(/:(.+)?/)[0]; 31 | title = article.split(/:(.+)?/)[1]; 32 | } else { 33 | language = 'en'; 34 | title = article; 35 | } 36 | if (!title) { 37 | return ''; 38 | } 39 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 40 | '?action=query' + 41 | '&list=backlinks' + 42 | '&bllimit=max' + 43 | '&blnamespace=' + (opt_namespaces ? 44 | encodeURIComponent(opt_namespaces) : '0') + 45 | '&format=xml' + 46 | '&bltitle=' + encodeURIComponent(title.replace(/\s/g, '_')); 47 | var xml = UrlFetchApp.fetch(url, { 48 | headers: { 49 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 50 | } 51 | }).getContentText(); 52 | var document = XmlService.parse(xml); 53 | var entries = document.getRootElement().getChild('query') 54 | .getChild('backlinks').getChildren('bl'); 55 | for (var i = 0; i < entries.length; i++) { 56 | var text = entries[i].getAttribute('title').getValue(); 57 | results[i] = text; 58 | } 59 | } catch (e) { 60 | // no-op 61 | } 62 | return results.length > 0 ? results : ''; 63 | } 64 | 65 | function WIKIOUTBOUNDLINKS_(article, opt_namespaces) { 66 | 'use strict'; 67 | if (!article) { 68 | return ''; 69 | } 70 | var results = []; 71 | try { 72 | var language; 73 | var title; 74 | if (article.indexOf(':') !== -1) { 75 | language = article.split(/:(.+)?/)[0]; 76 | title = article.split(/:(.+)?/)[1]; 77 | } else { 78 | language = 'en'; 79 | title = article; 80 | } 81 | if (!title) { 82 | return ''; 83 | } 84 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 85 | '?action=query' + 86 | '&prop=links' + 87 | '&plnamespace=' + (opt_namespaces ? 88 | encodeURIComponent(opt_namespaces) : '0') + 89 | '&format=xml' + 90 | '&pllimit=max' + 91 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 92 | var xml = UrlFetchApp.fetch(url, { 93 | headers: { 94 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 95 | } 96 | }).getContentText(); 97 | var document = XmlService.parse(xml); 98 | var entries = document.getRootElement().getChild('query').getChild('pages') 99 | .getChild('page').getChild('links').getChildren('pl'); 100 | for (var i = 0; i < entries.length; i++) { 101 | var text = entries[i].getAttribute('title').getValue(); 102 | results[i] = text; 103 | } 104 | } catch (e) { 105 | // no-op 106 | } 107 | return results.length > 0 ? results : ''; 108 | } 109 | 110 | -------------------------------------------------------------------------------- /functions/WIKIOUTBOUNDLINKS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia outbound links for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get outbound links for. 6 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 7 | * @return {Array} The list of outbound links. 8 | * @customfunction 9 | */ 10 | function WIKIOUTBOUNDLINKS(article, opt_namespaces) { 11 | 'use strict'; 12 | if (!article) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | var language; 18 | var title; 19 | if (article.indexOf(':') !== -1) { 20 | language = article.split(/:(.+)?/)[0]; 21 | title = article.split(/:(.+)?/)[1]; 22 | } else { 23 | language = 'en'; 24 | title = article; 25 | } 26 | if (!title) { 27 | return ''; 28 | } 29 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 30 | '?action=query' + 31 | '&prop=links' + 32 | '&plnamespace=' + (opt_namespaces ? 33 | encodeURIComponent(opt_namespaces) : '0') + 34 | '&format=xml' + 35 | '&pllimit=max' + 36 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 37 | var xml = UrlFetchApp.fetch(url, { 38 | headers: { 39 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 40 | } 41 | }).getContentText(); 42 | var document = XmlService.parse(xml); 43 | var entries = document.getRootElement().getChild('query').getChild('pages') 44 | .getChild('page').getChild('links').getChildren('pl'); 45 | for (var i = 0; i < entries.length; i++) { 46 | var text = entries[i].getAttribute('title').getValue(); 47 | results[i] = text; 48 | } 49 | } catch (e) { 50 | console.log(JSON.stringify(e)); 51 | } 52 | return results.length > 0 ? results : ''; 53 | } 54 | -------------------------------------------------------------------------------- /functions/WIKIPAGEEDITS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia pageedits statistics for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get pageedits statistics for. 6 | * @param {string=} opt_start The start date in the format "YYYYMMDD" ("2007-06-08") since when pageedits statistics should be retrieved from (optional). 7 | * @param {string=} opt_end The end date in the format "YYYYMMDD" ("2007-06-08") until when pageedits statistics should be retrieved to (optional). 8 | * @return {Array} The list of pageedits between start and end and their deltas. 9 | * @customfunction 10 | */ 11 | function WIKIPAGEEDITS(article, opt_start, opt_end) { 12 | 'use strict'; 13 | 14 | var getIsoDate = function (date, time) { 15 | var date = new Date(date); 16 | var year = date.getFullYear(); 17 | var month = (date.getMonth() + 1) < 10 ? 18 | '0' + (date.getMonth() + 1) : 19 | (date.getMonth() + 1).toString(); 20 | var day = date.getDate() < 10 ? 21 | '0' + date.getDate() : 22 | date.getDate().toString(); 23 | return year + '-' + month + '-' + day + time; 24 | }; 25 | 26 | if (!article) { 27 | return ''; 28 | } 29 | var results = []; 30 | try { 31 | var language; 32 | var title; 33 | if (article.indexOf(':') !== -1) { 34 | language = article.split(/:(.+)?/)[0]; 35 | title = article.split(/:(.+)?/)[1]; 36 | } else { 37 | language = 'en'; 38 | title = article; 39 | } 40 | if (!title) { 41 | return ''; 42 | } 43 | opt_start = opt_start || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); 44 | if (typeof opt_start === 'object') { 45 | opt_start = getIsoDate(opt_start, 'T00:00:00'); 46 | } 47 | opt_end = opt_end || new Date(); 48 | if (typeof opt_end === 'object') { 49 | opt_end = getIsoDate(opt_end, 'T23:59:59'); 50 | } 51 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 52 | '?action=query' + 53 | '&prop=revisions' + 54 | '&rvprop=size%7Ctimestamp' + 55 | '&rvlimit=max' + 56 | '&format=xml' + 57 | '&rvstart=' + opt_end + // Reversed on purpose due to confusing API name 58 | '&rvend=' + opt_start + // Reversed on purpose due to confusing API name 59 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 60 | var xml = UrlFetchApp.fetch(url, { 61 | headers: { 62 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 63 | } 64 | }).getContentText(); 65 | var document = XmlService.parse(xml); 66 | var entries = document.getRootElement().getChild('query').getChild('pages') 67 | .getChild('page').getChild('revisions').getChildren('rev'); 68 | for (var i = 0; i < entries.length - 1 /* - 1 for the delta */; i++) { 69 | var timestamp = entries[i].getAttribute('timestamp').getValue().replace( 70 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/, 71 | '$1-$2-$3-$4-$5-$6').split('-'); 72 | timestamp = new Date(Date.UTC( 73 | parseInt(timestamp[0], 10), // Year 74 | parseInt(timestamp[1], 10) - 1, // Month 75 | parseInt(timestamp[2], 10), // Day 76 | parseInt(timestamp[3], 10), // Hour 77 | parseInt(timestamp[4], 10), // Minute 78 | parseInt(timestamp[5], 10))); // Second 79 | var delta = entries[i].getAttribute('size').getValue() - 80 | entries[i + 1].getAttribute('size').getValue(); 81 | results.push([ 82 | timestamp, 83 | delta 84 | ]); 85 | } 86 | } catch (e) { 87 | console.log(JSON.stringify(e)); 88 | } 89 | return results.length > 0 ? results : ''; 90 | } 91 | -------------------------------------------------------------------------------- /functions/WIKIPAGEVIEWS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia pageviews statistics for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get pageviews statistics for. 6 | * @param {string=} opt_start The start date in the format "YYYYMMDD" ("20070608") since when pageviews statistics should be retrieved from (optional). 7 | * @param {string=} opt_end The end date in the format "YYYYMMDD" ("20070608") until when pageviews statistics should be retrieved to (optional). 8 | * @param {boolean=} opt_sumOnly Whether to only return the sum of all pageviews in the requested period (optional). 9 | * @return {Array} The list of pageviews between start and end per day. 10 | * @customfunction 11 | */ 12 | function WIKIPAGEVIEWS(article, opt_start, opt_end, opt_sumOnly) { 13 | 'use strict'; 14 | 15 | var getIsoDate = function (date) { 16 | var date = new Date(date); 17 | var year = date.getFullYear().toString(); 18 | var month = (date.getMonth() + 1) < 10 ? 19 | '0' + (date.getMonth() + 1) : 20 | (date.getMonth() + 1).toString(); 21 | var day = date.getDate() < 10 ? 22 | '0' + date.getDate() : 23 | date.getDate().toString(); 24 | return year + month + day; 25 | }; 26 | 27 | if (!article) { 28 | return ''; 29 | } 30 | var results = []; 31 | var sum = 0; 32 | try { 33 | var language; 34 | var title; 35 | if (article.indexOf(':') !== -1) { 36 | language = article.split(/:(.+)?/)[0]; 37 | title = article.split(/:(.+)?/)[1]; 38 | } else { 39 | language = 'en'; 40 | title = article; 41 | } 42 | if (!title) { 43 | return ''; 44 | } 45 | opt_start = opt_start || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); 46 | if (typeof opt_start === 'object') { 47 | opt_start = getIsoDate(opt_start); 48 | } 49 | opt_end = opt_end || new Date(Date.now() - 1 * 24 * 60 * 60 * 1000); 50 | if (typeof opt_end === 'object') { 51 | opt_end = getIsoDate(opt_end); 52 | } 53 | var url = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/' + 54 | 'per-article' + 55 | '/' + language + '.wikipedia' + 56 | '/all-access' + 57 | '/user' + 58 | '/' + encodeURIComponent(title.replace(/\s/g, '_')) + 59 | '/daily' + 60 | '/' + opt_start + 61 | '/' + opt_end; 62 | var json = JSON.parse(UrlFetchApp.fetch(url, { 63 | headers: { 64 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 65 | } 66 | }).getContentText()); 67 | json.items.forEach(function (item) { 68 | if (opt_sumOnly) { 69 | sum += item.views; 70 | } else { 71 | var timestamp = item.timestamp.replace(/^(\d{4})(\d{2})(\d{2})(\d{2})$/, 72 | '$1-$2-$3-$4').split('-'); 73 | timestamp = new Date(Date.UTC( 74 | parseInt(timestamp[0], 10), // Year 75 | parseInt(timestamp[1], 10) - 1, // Month 76 | parseInt(timestamp[2], 10), // Day 77 | parseInt(timestamp[3], 10), // Hour 78 | 0, // Minute 79 | 0)); // Second)) 80 | results.push([ 81 | timestamp, 82 | item.views 83 | ]); 84 | } 85 | }); 86 | } catch (e) { 87 | console.log(JSON.stringify(e)); 88 | } 89 | if (opt_sumOnly) { 90 | return [sum]; 91 | } else { 92 | results.reverse(); // Order from new to old 93 | return results.length > 0 ? results : ''; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /functions/WIKIPAGEVIEWSAGGREGATE.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns aggregated pageviews statistics for a project. 4 | * 5 | * @param {string} project The Wikimedia project to get pageviews statistics for. 6 | * @param {string=} opt_access The access method, defaults to "all-access" (optional). 7 | * @param {string=} opt_agent The agent, defaults to "all-agents" (optional). 8 | * @param {string=} opt_granularity The granularity, defaults to "daily" (optional). 9 | * @param {string=} opt_start The start date in the format "YYYYMMDDHH" ("2007060800") since when pageviews statistics should be retrieved from (optional). 10 | * @param {string=} opt_end The end date in the format "YYYYMMDDHH" ("2007060800") until when pageviews statistics should be retrieved to (optional). 11 | * @return {Array} The list of aggregated pageviews between start and end. 12 | * @customfunction 13 | */ 14 | function WIKIPAGEVIEWSAGGREGATE(project, opt_access, opt_agent, opt_granularity, 15 | opt_start, opt_end) { 16 | 'use strict'; 17 | 18 | var getIsoDateWithHour = function (date) { 19 | var date = new Date(date); 20 | var year = date.getFullYear().toString(); 21 | var month = (date.getMonth() + 1) < 10 ? 22 | '0' + (date.getMonth() + 1) : 23 | (date.getMonth() + 1).toString(); 24 | var day = date.getDate() < 10 ? 25 | '0' + date.getDate() : 26 | date.getDate().toString(); 27 | return year + month + day + '00'; 28 | }; 29 | 30 | if (!project) { 31 | return ''; 32 | } 33 | var results = []; 34 | try { 35 | opt_start = opt_start || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); 36 | if (typeof opt_start === 'object') { 37 | opt_start = getIsoDateWithHour(opt_start); 38 | } 39 | opt_end = opt_end || new Date(Date.now() - 1 * 24 * 60 * 60 * 1000); 40 | if (typeof opt_end === 'object') { 41 | opt_end = getIsoDateWithHour(opt_end); 42 | } 43 | var url = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/' + 44 | 'aggregate' + 45 | '/' + project + 46 | '/' + (opt_access ? opt_access : 'all-access') + 47 | '/' + (opt_agent ? opt_agent : 'all-agents') + 48 | '/' + (opt_granularity ? opt_granularity : 'daily') + 49 | '/' + opt_start + 50 | '/' + opt_end; 51 | var json = JSON.parse(UrlFetchApp.fetch(url, { 52 | headers: { 53 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 54 | } 55 | }).getContentText()); 56 | json.items.forEach(function (item) { 57 | var timestamp = item.timestamp.replace(/^(\d{4})(\d{2})(\d{2})(\d{2})$/, 58 | '$1-$2-$3-$4').split('-'); 59 | timestamp = new Date(Date.UTC( 60 | parseInt(timestamp[0], 10), // Year 61 | parseInt(timestamp[1], 10) - 1, // Month 62 | parseInt(timestamp[2], 10), // Day 63 | parseInt(timestamp[3], 10), // Hour 64 | 0, // Minute 65 | 0)); // Second)) 66 | results.push([ 67 | timestamp, 68 | item.views 69 | ]); 70 | }); 71 | } catch (e) { 72 | console.log(JSON.stringify(e)); 73 | } 74 | results.reverse(); // Order from new to old 75 | return results.length > 0 ? results : ''; 76 | } 77 | -------------------------------------------------------------------------------- /functions/WIKIPAGEVIEWSPERARTICLE.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns pageviews statistics for individual pages. 4 | * 5 | * @param {string} project The Wikimedia project to get pageviews statistics for. 6 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get pageviews statistics for. 7 | * @param {string=} opt_access The access method, defaults to "all-access" (optional). 8 | * @param {string=} opt_agent The agent, defaults to "all-agents" (optional). 9 | * @param {string=} opt_granularity The granularity, defaults to "daily" (optional). 10 | * @param {string=} opt_start The start date in the format "YYYYMMDD" ("20070608") since when pageviews statistics should be retrieved from (optional). 11 | * @param {string=} opt_end The end date in the format "YYYYMMDD" ("20070608") until when pageviews statistics should be retrieved to (optional). 12 | * @param {boolean=} opt_sumOnly Whether to only return the sum of all pageviews in the requested period (optional). 13 | * @return {Array} The list of pageviews between start and end. 14 | * @customfunction 15 | */ 16 | function WIKIPAGEVIEWSPERARTICLE(project, article, opt_access, 17 | opt_agent, opt_granularity, opt_start, opt_end, opt_sumOnly) { 18 | 'use strict'; 19 | 20 | var getIsoDate = function (date) { 21 | var date = new Date(date); 22 | var year = date.getFullYear().toString(); 23 | var month = (date.getMonth() + 1) < 10 ? 24 | '0' + (date.getMonth() + 1) : 25 | (date.getMonth() + 1).toString(); 26 | var day = date.getDate() < 10 ? 27 | '0' + date.getDate() : 28 | date.getDate().toString(); 29 | return year + month + day; 30 | }; 31 | 32 | if (!project) { 33 | return ''; 34 | } 35 | if (!article) { 36 | return ''; 37 | } 38 | var results = []; 39 | var sum = 0; 40 | try { 41 | opt_start = opt_start || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); 42 | if (typeof opt_start === 'object') { 43 | opt_start = getIsoDate(opt_start); 44 | } 45 | opt_end = opt_end || new Date(Date.now() - 1 * 24 * 60 * 60 * 1000); 46 | if (typeof opt_end === 'object') { 47 | opt_end = getIsoDate(opt_end); 48 | } 49 | var url = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/' + 50 | 'per-article' + 51 | '/' + project + 52 | '/' + (opt_access ? opt_access : 'all-access') + 53 | '/' + (opt_agent ? opt_agent : 'all-agents') + 54 | '/' + encodeURIComponent(article.replace(/\s/g, '_')) + 55 | '/' + (opt_granularity ? opt_granularity : 'daily') + 56 | '/' + opt_start + 57 | '/' + opt_end; 58 | var json = JSON.parse(UrlFetchApp.fetch(url, { 59 | headers: { 60 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 61 | } 62 | }).getContentText()); 63 | json.items.forEach(function (item) { 64 | if (opt_sumOnly) { 65 | sum += item.views; 66 | } else { 67 | var timestamp = item.timestamp.replace(/^(\d{4})(\d{2})(\d{2})(\d{2})$/, 68 | '$1-$2-$3-$4').split('-'); 69 | timestamp = new Date(Date.UTC( 70 | parseInt(timestamp[0], 10), // Year 71 | parseInt(timestamp[1], 10) - 1, // Month 72 | parseInt(timestamp[2], 10), // Day 73 | parseInt(timestamp[3], 10), // Hour 74 | 0, // Minute 75 | 0)); // Second)) 76 | results.push([ 77 | timestamp, 78 | item.views 79 | ]); 80 | } 81 | }); 82 | } catch (e) { 83 | console.log(JSON.stringify(e)); 84 | } 85 | if (opt_sumOnly) { 86 | return [sum]; 87 | } else { 88 | results.reverse(); // Order from new to old 89 | return results.length > 0 ? results : ''; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /functions/WIKIPAGEVIEWSTOP.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns most viewed pages for a project. 4 | * 5 | * @param {string} project The Wikimedia project to get pageviews statistics for. 6 | * @param {string=} opt_access The access method, defaults to "all-access" (optional). 7 | * @param {string=} opt_date The date in the format "YYYYMMDD" ("20070608") for which pageviews statistics should be retrieved (optional). 8 | * @return {Array} The list of the most viewed pages. 9 | * @customfunction 10 | */ 11 | function WIKIPAGEVIEWSTOP(project, opt_access, opt_date) { 12 | 'use strict'; 13 | 14 | var getIsoDate = function (date) { 15 | var date = new Date(date); 16 | var year = date.getFullYear().toString(); 17 | var month = (date.getMonth() + 1) < 10 ? 18 | '0' + (date.getMonth() + 1) : 19 | (date.getMonth() + 1).toString(); 20 | var day = date.getDate() < 10 ? 21 | '0' + date.getDate() : 22 | date.getDate().toString(); 23 | return year + month + day; 24 | }; 25 | 26 | if (!project) { 27 | return ''; 28 | } 29 | var results = []; 30 | var sum = 0; 31 | try { 32 | opt_date = opt_date || new Date(Date.now() - 1 * 24 * 60 * 60 * 1000); 33 | if (typeof opt_date === 'object') { 34 | opt_date = getIsoDate(opt_date); 35 | } 36 | var year = opt_date.substr(0, 4); 37 | var month = opt_date.substring(4, 6); 38 | var day = opt_date.substring(6, 8); 39 | var url = 'https://wikimedia.org/api/rest_v1/metrics/pageviews/' + 40 | 'top' + 41 | '/' + project + 42 | '/' + (opt_access ? opt_access : 'all-access') + 43 | '/' + year + 44 | '/' + month + 45 | '/' + day; 46 | var json = JSON.parse(UrlFetchApp.fetch(url, { 47 | headers: { 48 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 49 | } 50 | }).getContentText()); 51 | json.items[0].articles.forEach(function (article) { 52 | results.push([ 53 | article.article.replace(/_/g, ' '), 54 | article.views 55 | ]); 56 | }); 57 | } catch (e) { 58 | console.log(JSON.stringify(e)); 59 | } 60 | return results.length > 0 ? results : ''; 61 | } 62 | -------------------------------------------------------------------------------- /functions/WIKIQUARRY.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the output of the Quarry (https://meta.wikimedia.org/wiki/Research:Quarry) query with the specified query ID. 4 | * 5 | * @param {number} queryId The query ID of the Quarry query to run. 6 | * @return {Array} The list of query results, the first line represents the header. 7 | * @customfunction 8 | */ 9 | function WIKIQUARRY(queryId) { 10 | 'use strict'; 11 | if (!queryId) { 12 | return ''; 13 | } 14 | var results = []; 15 | try { 16 | var url = 'https://quarry.wmflabs.org/query/' + queryId + 17 | '/result/latest/0/json'; 18 | var json = JSON.parse(UrlFetchApp.fetch(url, { 19 | headers: { 20 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 21 | } 22 | }).getContentText()); 23 | results[0] = json.headers; 24 | results = results.concat(json.rows); 25 | } catch (e) { 26 | console.log(JSON.stringify(e)); 27 | } 28 | return results.length > 0 ? results : ''; 29 | } 30 | -------------------------------------------------------------------------------- /functions/WIKISEARCH.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia article results for a query. 4 | * 5 | * @param {string} query The query in the format "language:Query" ("de:Berlin") to get search results for. 6 | * @param {boolean=} opt_didYouMean Whether to return a "did you mean" suggestion, defaults to false (optional). 7 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 8 | * @return {Array} The list of article results. 9 | * @customfunction 10 | */ 11 | function WIKISEARCH(query, opt_didYouMean, opt_namespaces) { 12 | 'use strict'; 13 | if (!query) { 14 | return ''; 15 | } 16 | var results = []; 17 | try { 18 | var language; 19 | var title; 20 | if (query.indexOf(':') !== -1) { 21 | language = query.split(/:(.+)?/)[0]; 22 | title = query.split(/:(.+)?/)[1]; 23 | } else { 24 | language = 'en'; 25 | title = query; 26 | } 27 | if (!title) { 28 | return ''; 29 | } 30 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 31 | '?action=query' + 32 | '&format=json' + 33 | '&list=search' + 34 | '&srinfo=suggestion' + 35 | '&srprop=' + // Empty on purpose 36 | '&srlimit=max' + 37 | '&srsearch=' + encodeURIComponent(title) + 38 | '&srnamespace=' + (opt_namespaces ? 39 | encodeURIComponent(opt_namespaces) : '0'); 40 | var json = JSON.parse(UrlFetchApp.fetch(url, { 41 | headers: { 42 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 43 | } 44 | }).getContentText()); 45 | json.query.search.forEach(function (result, i) { 46 | result = result.title; 47 | if (opt_didYouMean) { 48 | if (i === 0) { 49 | results[i] = [ 50 | result, 51 | json.query.searchinfo ? json.query.searchinfo.suggestion : title 52 | ]; 53 | } else { 54 | results[i] = [result, '']; 55 | } 56 | } else { 57 | results[i] = result; 58 | } 59 | }); 60 | } catch (e) { 61 | console.log(JSON.stringify(e)); 62 | } 63 | return results.length > 0 ? results : ''; 64 | } 65 | -------------------------------------------------------------------------------- /functions/WIKISUBCATEGORIES.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia subcategories for a Wikipedia category. 4 | * 5 | * @param {string} category The Wikipedia category in the format "language:Category_Title" ("en:Category:Visitor_attractions_in_Berlin") to get subcategories for. 6 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 7 | * @return {Array} The list of subcategories. 8 | * @customfunction 9 | */ 10 | function WIKISUBCATEGORIES(category, opt_namespaces) { 11 | 'use strict'; 12 | if (!category) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | var language; 18 | var title; 19 | if ((category.match(/:/g) || []).length > 1) { 20 | language = category.split(/:(.+)?/)[0]; 21 | title = category.split(/:(.+)?/)[1]; 22 | } else { 23 | language = 'en'; 24 | title = category; 25 | } 26 | if (!title) { 27 | return ''; 28 | } 29 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 30 | '?action=query' + 31 | '&list=categorymembers' + 32 | '&cmlimit=max' + 33 | '&cmprop=title' + 34 | '&cmtype=subcat%7Cpage' + 35 | '&format=xml' + 36 | '&cmnamespace=' + (opt_namespaces ? 37 | encodeURIComponent(opt_namespaces) : '14') + 38 | '&cmtitle=' + encodeURIComponent(title.replace(/\s/g, '_')); 39 | var xml = UrlFetchApp.fetch(url, { 40 | headers: { 41 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 42 | } 43 | }).getContentText(); 44 | var document = XmlService.parse(xml); 45 | var entries = document.getRootElement().getChild('query') 46 | .getChild('categorymembers').getChildren('cm'); 47 | for (var i = 0; i < entries.length; i++) { 48 | var text = entries[i].getAttribute('title').getValue(); 49 | results[i] = text; 50 | } 51 | } catch (e) { 52 | console.log(JSON.stringify(e)); 53 | } 54 | return results.length > 0 ? results : ''; 55 | } 56 | -------------------------------------------------------------------------------- /functions/WIKISYNONYMS.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia synonyms (redirects) for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get synonyms for. 6 | * @param {string=} opt_namespaces Only include pages in these namespaces (optional). 7 | * @return {Array} The list of synonyms. 8 | * @customfunction 9 | */ 10 | function WIKISYNONYMS(article, opt_namespaces) { 11 | 'use strict'; 12 | if (!article) { 13 | return ''; 14 | } 15 | var results = []; 16 | try { 17 | var language; 18 | var title; 19 | if (article.indexOf(':') !== -1) { 20 | language = article.split(/:(.+)?/)[0]; 21 | title = article.split(/:(.+)?/)[1]; 22 | } else { 23 | language = 'en'; 24 | title = article; 25 | } 26 | if (!title) { 27 | return ''; 28 | } 29 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 30 | '?action=query' + 31 | '&blnamespace=' + (opt_namespaces ? 32 | encodeURIComponent(opt_namespaces) : '0') + 33 | '&list=backlinks' + 34 | '&blfilterredir=redirects' + 35 | '&bllimit=max' + 36 | '&format=xml' + 37 | '&bltitle=' + encodeURIComponent(title.replace(/\s/g, '_')); 38 | var xml = UrlFetchApp.fetch(url, { 39 | headers: { 40 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 41 | } 42 | }).getContentText(); 43 | var document = XmlService.parse(xml); 44 | var entries = document.getRootElement().getChild('query') 45 | .getChild('backlinks').getChildren('bl'); 46 | for (var i = 0; i < entries.length; i++) { 47 | var text = entries[i].getAttribute('title').getValue(); 48 | results[i] = text; 49 | } 50 | } catch (e) { 51 | console.log(JSON.stringify(e)); 52 | } 53 | return results.length > 0 ? results : ''; 54 | } -------------------------------------------------------------------------------- /functions/WIKITRANSLATE.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns Wikipedia translations (language links) for a Wikipedia article. 4 | * 5 | * @param {string} article The Wikipedia article in the format "language:Article_Title" ("de:Berlin") to get translations for. 6 | * @param {Array=} opt_targetLanguages The list of languages to limit the results to (optional). 7 | * @param {boolean=} opt_skipHeader Whether to skip the header, defaults to false (optional). 8 | * @return {Array} The list of translations. 9 | * @customfunction 10 | */ 11 | function WIKITRANSLATE(article, opt_targetLanguages, opt_skipHeader, 12 | _opt_returnAsObject) { 13 | 'use strict'; 14 | if (!article) { 15 | return ''; 16 | } 17 | var results = {}; 18 | opt_targetLanguages = opt_targetLanguages || []; 19 | opt_targetLanguages = Array.isArray(opt_targetLanguages) ? 20 | opt_targetLanguages : [opt_targetLanguages]; 21 | var temp = {}; 22 | opt_targetLanguages.forEach(function (lang) { 23 | temp[lang] = true; 24 | }); 25 | opt_targetLanguages = Object.keys(temp); 26 | try { 27 | var language; 28 | var title; 29 | if (article.indexOf(':') !== -1) { 30 | language = article.split(/:(.+)?/)[0]; 31 | title = article.split(/:(.+)?/)[1]; 32 | } else { 33 | language = 'en'; 34 | title = article; 35 | } 36 | if (!title) { 37 | return ''; 38 | } 39 | opt_targetLanguages.forEach(function (targetLanguage) { 40 | if (targetLanguage) { 41 | results[targetLanguage] = title.replace(/_/g, ' '); 42 | } 43 | }); 44 | var url = 'https://' + language + '.wikipedia.org/w/api.php' + 45 | '?action=query' + 46 | '&prop=langlinks' + 47 | '&format=xml' + 48 | '&lllimit=max' + 49 | '&titles=' + encodeURIComponent(title.replace(/\s/g, '_')); 50 | var xml = UrlFetchApp.fetch(url, { 51 | headers: { 52 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 53 | } 54 | }).getContentText(); 55 | var document = XmlService.parse(xml); 56 | var entries = document.getRootElement().getChild('query').getChild('pages') 57 | .getChild('page').getChild('langlinks').getChildren('ll'); 58 | var targetLanguagesSet = opt_targetLanguages.length > 0; 59 | for (var i = 0; i < entries.length; i++) { 60 | var text = entries[i].getText(); 61 | var lang = entries[i].getAttribute('lang').getValue(); 62 | if ((targetLanguagesSet) && (opt_targetLanguages.indexOf(lang) === -1)) { 63 | continue; 64 | } 65 | results[lang] = text; 66 | } 67 | title = title.replace(/_/g, ' '); 68 | results[language] = title; 69 | } catch (e) { 70 | console.log(JSON.stringify(e)); 71 | } 72 | if (_opt_returnAsObject) { 73 | return results; 74 | } 75 | var arrayResults = []; 76 | for (var lang in results) { 77 | if (opt_skipHeader) { 78 | arrayResults.push(results[lang]); 79 | } else { 80 | arrayResults.push([lang, results[lang]]); 81 | } 82 | } 83 | return arrayResults.length > 0 ? arrayResults : ''; 84 | } 85 | -------------------------------------------------------------------------------- /functions/WIKIUNIQUEDEVICES.gs: -------------------------------------------------------------------------------- 1 | // @author Thomas Steiner https://github.com/tomayac/wikipedia-tools-for-google-spreadsheets 2 | /** 3 | * Returns the number of unique devices for a project. 4 | * 5 | * @param {string} project The Wikimedia project to get pageviews statistics for. 6 | * @param {string=} opt_accessSite The accesses sites, defaults to "all-sites" (optional). 7 | * @param {string=} opt_granularity The granularity, defaults to "daily" (optional). 8 | * @param {string=} opt_start The start date in the format "YYYYMMDD" ("20070608") since when pageviews statistics should be retrieved from (optional). 9 | * @param {string=} opt_end The end date in the format "YYYYMMDD" ("20070608") until when pageviews statistics should be retrieved to (optional). 10 | * @return {Array} The list of unique devices between start and end. 11 | * @customfunction 12 | */ 13 | function WIKIUNIQUEDEVICES(project, opt_accessSite, opt_granularity, opt_start, 14 | opt_end) { 15 | 'use strict'; 16 | 17 | var getIsoDate = function (date) { 18 | var date = new Date(date); 19 | var year = date.getFullYear().toString(); 20 | var month = (date.getMonth() + 1) < 10 ? 21 | '0' + (date.getMonth() + 1) : 22 | (date.getMonth() + 1).toString(); 23 | var day = date.getDate() < 10 ? 24 | '0' + date.getDate() : 25 | date.getDate().toString(); 26 | return year + month + day; 27 | }; 28 | 29 | if (!project) { 30 | return ''; 31 | } 32 | var results = []; 33 | var sum = 0; 34 | try { 35 | opt_start = opt_start || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); 36 | if (typeof opt_start === 'object') { 37 | opt_start = getIsoDate(opt_start); 38 | } 39 | opt_end = opt_end || new Date(Date.now() - 1 * 24 * 60 * 60 * 1000); 40 | if (typeof opt_end === 'object') { 41 | opt_end = getIsoDate(opt_end); 42 | } 43 | var url = 'https://wikimedia.org/api/rest_v1/metrics/unique-devices' + 44 | '/' + project + 45 | '/' + (opt_accessSite ? opt_accessSite : 'all-sites') + 46 | '/' + (opt_granularity ? opt_granularity : 'daily') + 47 | '/' + opt_start + 48 | '/' + opt_end; 49 | var json = JSON.parse(UrlFetchApp.fetch(url, { 50 | headers: { 51 | 'X-User-Agent': 'Wikipedia Tools for Google Spreadsheets' 52 | } 53 | }).getContentText()); 54 | json.items.forEach(function (item) { 55 | var timestamp = item.timestamp.replace(/^(\d{4})(\d{2})(\d{2})$/, 56 | '$1-$2-$3').split('-'); 57 | timestamp = new Date(Date.UTC( 58 | parseInt(timestamp[0], 10), // Year 59 | parseInt(timestamp[1], 10) - 1, // Month 60 | parseInt(timestamp[2], 10), // Day 61 | 0, // Hour 62 | 0, // Minute 63 | 0)); // Second)) 64 | results.push([ 65 | timestamp, 66 | item.devices 67 | ]); 68 | }); 69 | } catch (e) { 70 | console.log(JSON.stringify(e)); 71 | } 72 | return results.length > 0 ? results : ''; 73 | } 74 | --------------------------------------------------------------------------------