diff options
| -rwxr-xr-x | gdocs.js | 199 | 
1 files changed, 199 insertions, 0 deletions
| diff --git a/gdocs.js b/gdocs.js new file mode 100755 index 00000000..4507931d --- /dev/null +++ b/gdocs.js @@ -0,0 +1,199 @@ +#!/usr/bin/env node +var http = require('http'); +var https = require('https'); +var fs = require('fs'); + +console.log('Google Docs...'); + +var flag = process && process.argv[2]; +if (flag == '--login') +  askPassword(function(password){ +    login(process.argv[3], password); +  }); +else if (flag == '--fetch') +  fetch(); +else +  help(); + +function help(){ +  console.log('Synopsys'); +  console.log('gdocs.js [--login|--fetch]'); +  process.exit(-1); +}; + + +function fetch(){ +  //https://docs.google.com/feeds/default/private/full/folder%3Afolder_id/contents +  console.log('fetching a list of docs...'); +  request('GET', 'http://docs.google.com/feeds/default/private/full/folder%3A0B7Ovm8bUYiUDZDJmNzI3NjItODY1NS00YTg3LWE2MDItNmMyODE4MDdhNDFk/contents', { +        headers: { +          'Gdata-Version': '3.0', +          'Authorization': 'GoogleLogin auth=' + getAuthToken() +        } +      }, +      function(chunk){ +        var entries = chunk.split('<entry'); +        entries.shift(); +        entries.forEach(function(entry){ +          var title = entry.match(/<title>(.*?)<\/title>/)[1]; +          if (title.match(/\.ngdoc$/)) { +            var exportUrl = entry.match(/<content type='text\/html' src='(.*?)'\/>/)[1]; +            download(title, exportUrl); +          } +        }); +      } +    ); +} + +function download(name, url) { +  console.log('Downloading:', name, '...'); +  request('GET', url + '&exportFormat=txt', +      { +        headers: { +          'Gdata-Version': '3.0', +          'Authorization': 'GoogleLogin auth=' + getAuthToken() +        } +      }, +      function(data){ +        data = data.replace('\ufeff', ''); +        data = data.replace(/\r\n/mg, '\n'); + +        // strip out all text annotation comments +        data = data.replace(/^\[a\][\S\s]*/m, ''); + +        // strip out all text annotations +        data = data.replace(/\[\w{1,3}\]/mg, ''); + +        data = data + '\n'; +        fs.writeFileSync('docs/' + name, reflow(data, 100)); +      } +    ); +} + +/** + * token=$(curl + *    -s https://www.google.com/accounts/ClientLogin + *    -d Email=...username... + *    -d Passwd=...password... + *    -d accountType=GOOGLE + *    -d service=writely + *    -d Gdata-version=3.0 | cut -d "=" -f 2) + */ +function login(username, password){ +  request('POST', 'https://www.google.com/accounts/ClientLogin', +      { +        data: { +          Email: username, +          Passwd: password, +          accountType: 'GOOGLE', +          service: 'writely', +          'Gdata-version': '3.0' +        }, +        headers: { +          'Content-type': 'application/x-www-form-urlencoded' +        } +      }, +      function(chunk){ +        var token; +        chunk.split('\n').forEach(function(line){ +          var parts = line.split('='); +          if (parts[0] == 'Auth') { +            token = parts[1]; +          } +        }); +        if (token) { +          fs.writeFileSync('tmp/gdocs.auth', token); +          console.log("logged in, token saved in 'tmp/gdocs.auth'"); +        } else { +          console.log('failed to log in'); +        } +      } +    ); +} + +function getAuthToken(){ +  return fs.readFileSync('tmp/gdocs.auth'); +} + +function request(method, url, options, response) { +  var url = url.match(/http(s?):\/\/(.+?)(\/.*)/); +  var request = (url[1] ? https : http).request({ +    host: url[2], +    port: (url[1] ? 443 : 80), +    path: url[3], +    method: method +  }, function(res){ +    var data = []; +    res.setEncoding('utf8'); +    res.on('end', function(){ +      response(data.join('')); +    }); +    res.on('data', function (chunk) { +      data.push(chunk); +    }); +  }); +  for(var header in options.headers) { +    request.setHeader(header, options.headers[header]); +  } +  if (options.data) +    request.write(encodeData(options.data)); +  request.on('end', function(){ +    console.log('end'); +  }); +  request.end(); +} + +function encodeData(obj) { +  var pairs = []; +  for(var key in obj) { +    pairs.push(key + '=' + obj[key]); +  } +  return pairs.join('&') + '\n'; +} + +function askPassword(callback) { +  var stdin = process.openStdin(), +      stdio = process.binding("stdio"); + +  stdio.setRawMode(); + +  console.log('Enter your password:'); +  var password = "" +  stdin.on("data", function (c) { +    c = c + ""; +    switch (c) { +      case "\n": case "\r": case "\u0004": +        stdio.setRawMode(false); +        stdin.pause(); +        callback(password); +        break; +      case "\u0003": +        process.exit(); +        break; +      default: +        password += c; +        break; +    } +  }) + +} + +function reflow(text, margin) { +  var lines = []; +  text.split(/\n/).forEach(function(line) { +    var col = 0; +    var reflowLine = ''; +    function flush(){ +      lines.push(reflowLine); +      reflowLine = ''; +      col = 0; +    } +    line.replace(/\s*\S*\s*/g, function(chunk){ +      if (col + chunk.length > margin) flush(); +      reflowLine += chunk; +      col += chunk.length; +    }); +    flush(); +  }); +  return lines.join('\n'); +} | 
