empyrean 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Empyrean
2
+
3
+ Generate full stats of your account using your Twitter Archive.
4
+
5
+ ## Usage
6
+
7
+ 1. Install Empyrean using `gem install empyrean`
8
+ 1. Download your Twitter archive and unpack it somewhere.
9
+ 2. Generate a new configuration file: `empyrean -g config.yml`
10
+ 2. `empyrean -d path/to/data/js/tweets`
11
+ 3. ???
12
+ 4. Profit!
13
+
14
+ ## Configuration
15
+
16
+ Configuration is done using the `config.yml` file in the current directory.
17
+ You can generate one using `empyrean -g config.yml`. You may also specify a
18
+ different configuration file to use with the `-c` switch.
19
+
20
+ You can also use the `-C` switch to override config values on the fly, such as
21
+ `-C timezone_difference=2` or `-C mentions_enabled=no`. If the configuration
22
+ variable is a list, separate the elements with `,`. For example, to ignore
23
+ the Twitter users `BarackObama` and `baddragon_en`, use
24
+ `-C ignored_users=BarackObama,baddragon_en`.
25
+
data/bin/empyrean ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ # empyrean - generate a statistics page from your Twitter archive
3
+ #
4
+ # This file is part of Empyrean
5
+ # Copyright (C) 2015 nilsding, pixeldesu
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+
20
+ require 'empyrean/cli'
21
+
22
+ Empyrean::CLI.new(*ARGV)
@@ -0,0 +1,31 @@
1
+ # Empyrean config file
2
+
3
+ timezone_difference: 0 # Time zone difference (e.g. 2 for UTC+2, -6 for UTC-6)
4
+
5
+ mentions:
6
+ enabled: true # Enable "Most mentioned users" list
7
+ top: 10 # How many users to show on the "Most mentioned users" list
8
+ notop: 20 # How many users to show on the "These didn't make it to the top" list
9
+ clients:
10
+ enabled: true # Enable "Most used clients" list
11
+ top: 10 # How many clients to show on the "Most used clients" list
12
+ notop: 20 # How many clients to show on the "These didn't make it to the top" list
13
+ hashtags:
14
+ enabled: true # Enable "Most used hashtags" list
15
+ top: 10 # How many hashtags to show on the "Most used hashtags" list
16
+ notop: 20 # How many hashtags to show on the "These didn't make it to the top" list
17
+ smileys:
18
+ enabled: true # Enable "Most used smileys" list
19
+ top: 10 # How many smileys to show on the "Most used smileys" list
20
+ notop: 0 # How many smileys to show on the "These didn't make it to the top" list
21
+
22
+ ignored_users: # Users to exclude from the statistics.
23
+ - BarackObama
24
+ - tbhjuststop
25
+
26
+ renamed_users: # Users that have renamed themselves
27
+ pixeldesu: "mochizune" # mochizune was previously known as pixeldesu
28
+ technikaflash: "mochizune" # mochizune was also previously known as TechnikaFlash (the downcase on the username is important)
29
+ traxxed22: "mochizune" # and before that, mochizune was known as TraXXed22.
30
+
31
+ # kate: indent-width 2
data/empyrean.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'empyrean/defaults'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'empyrean'
8
+ spec.version = Empyrean::VERSION
9
+ spec.authors = ['nilsding', 'pixeldesu']
10
+ spec.email = ['nilsding@nilsding.org', 'andy@pixelde.su']
11
+ spec.summary = %q{Generates stats using your Twitter archive.}
12
+ spec.description = %q{With Empyrean, you can generate full stats of your Twitter account using your Twitter archive.}
13
+ spec.homepage = 'https://github.com/Leafcat/Empyrean'
14
+ spec.license = 'GPLv3'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+ end
@@ -0,0 +1,97 @@
1
+ # cli.rb
2
+ #
3
+ # This file is part of Empyrean
4
+ # Copyright (C) 2015 nilsding, pixeldesu
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require 'empyrean/defaults'
20
+ require 'empyrean/optparser'
21
+ require 'empyrean/configloader'
22
+ require 'empyrean/tweetloader'
23
+ require 'empyrean/tweetparser'
24
+ require 'empyrean/templatelister'
25
+ require 'empyrean/templaterenderer'
26
+
27
+ module Empyrean
28
+ class CLI
29
+ def initialize(*argv)
30
+ @options = OptParser.parse(argv)
31
+ @config = ConfigLoader.new(@options).load_config
32
+
33
+ parsed = analyze_tweets
34
+ print_stats(parsed)
35
+ generate_html(parsed)
36
+ end
37
+
38
+ def analyze_tweets
39
+ tweet_files = TweetLoader.read_directory(@options.jsondir)
40
+ parsed = []
41
+ parser = TweetParser.new(@options, @config)
42
+ tweet_files.each do |file|
43
+ tweet = TweetLoader.read_file file
44
+ parsed << parser.parse(tweet)
45
+ end
46
+ TweetParser.merge_parsed parsed
47
+ end
48
+
49
+ def print_stats(parsed)
50
+ puts "Analyzed #{parsed[:tweet_count]} tweets"
51
+ puts " - #{(parsed[:retweet_count] * 100 / parsed[:tweet_count].to_f).round(2)}% retweets\n"
52
+ return unless @options.print_stats
53
+
54
+ headers = {
55
+ mentions: ["You send most mentions to:", "times", :name],
56
+ clients: ["Most used clients:", "tweets", :name],
57
+ hashtags: ["Your most used hashtags:", "times", :hashtag],
58
+ smileys: ["Your most used smileys:", "times", :smiley]
59
+ }
60
+
61
+ headers.each do |k, v|
62
+ if @config[k][:enabled]
63
+ puts v[0]
64
+ begin
65
+ @config[k][:top].times do |i|
66
+ puts "#{sprintf "%2d", i + 1}. #{'#' if k == :hashtags}#{parsed[k][i][1][v[2]]} (#{parsed[k][i][1][:count]} #{v[1]})"
67
+ end
68
+ rescue => _
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def generate_html(parsed)
75
+ puts "Generating HTML"
76
+ template = File.read template_file
77
+ renderer = TemplateRenderer.new @config, template, parsed
78
+ File.open(@options.outfile, 'w') do |outfile|
79
+ outfile.write renderer.render
80
+ outfile.flush
81
+ end
82
+ puts " => #{@options.outfile}"
83
+ end
84
+
85
+ def template_file
86
+ if File.exist? File.join(Dir.pwd, @options.template)
87
+ File.join(Dir.pwd, @options.template)
88
+ elsif TemplateLister.list.include? @options.template
89
+ File.join TEMPLATE_DIR, @options.template
90
+ else
91
+ @options.template
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ # kate: indent-width 2
@@ -0,0 +1,105 @@
1
+ # configloader.rb - loads a config file
2
+ #
3
+ # This file is part of Empyrean
4
+ # Copyright (C) 2015 nilsding, pixeldesu
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require 'yaml'
20
+ require 'empyrean/defaults'
21
+
22
+ module Empyrean
23
+ class ConfigLoader
24
+ def initialize(options)
25
+ @options = options
26
+ end
27
+
28
+ ##
29
+ # Loads a YAML file, parses it and returns a hash with symbolized keys.
30
+ def load(file)
31
+ if File.exist? file
32
+ symbolize_keys(YAML.load_file(File.expand_path('.', file)))
33
+ else
34
+ {}
35
+ end
36
+ end
37
+
38
+ # Loads a YAML file, parses it and checks if all values are given. If a
39
+ # value is missing, it will be set with the default value.
40
+ def load_config(file = @options.config)
41
+ config = load(file)
42
+ config[:timezone_difference] = 0 if config[:timezone_difference].nil?
43
+ config[:mentions] = {} if config[:mentions].nil?
44
+ config[:mentions][:enabled] = true if config[:mentions][:enabled].nil?
45
+ config[:mentions][:top] = 10 if config[:mentions][:top].nil?
46
+ config[:mentions][:notop] = 20 if config[:mentions][:notop].nil?
47
+ config[:clients] = {} if config[:clients].nil?
48
+ config[:clients][:enabled] = true if config[:clients][:enabled].nil?
49
+ config[:clients][:top] = 10 if config[:clients][:top].nil?
50
+ config[:clients][:notop] = 20 if config[:clients][:notop].nil?
51
+ config[:hashtags] = {} if config[:hashtags].nil?
52
+ config[:hashtags][:enabled] = true if config[:hashtags][:enabled].nil?
53
+ config[:hashtags][:top] = 10 if config[:hashtags][:top].nil?
54
+ config[:hashtags][:notop] = 20 if config[:hashtags][:notop].nil?
55
+ config[:smileys] = {} if config[:smileys].nil?
56
+ config[:smileys][:enabled] = true if config[:smileys][:enabled].nil?
57
+ config[:smileys][:top] = 10 if config[:smileys][:top].nil?
58
+ config[:smileys][:notop] = 0 if config[:smileys][:notop].nil?
59
+ config[:ignored_users] = [] if config[:ignored_users].nil?
60
+ config[:renamed_users] = [] if config[:renamed_users].nil?
61
+ args_override config
62
+ end
63
+
64
+ def args_override(config)
65
+ config_args = @options.config_values
66
+ config[:timezone_difference] = config_args[:timezone_difference] unless config_args[:timezone_difference].nil?
67
+ config[:mentions][:enabled] = config_args[:mentions_enabled] unless config_args[:mentions_enabled].nil?
68
+ config[:mentions][:top] = config_args[:mentions_top] unless config_args[:mentions_top].nil?
69
+ config[:mentions][:notop] = config_args[:mentions_notop] unless config_args[:mentions_notop].nil?
70
+ config[:clients][:enabled] = config_args[:clients_enabled] unless config_args[:clients_enabled].nil?
71
+ config[:clients][:top] = config_args[:clients_top] unless config_args[:clients_top].nil?
72
+ config[:clients][:notop] = config_args[:clients_notop] unless config_args[:clients_notop].nil?
73
+ config[:hashtags][:enabled] = config_args[:hashtags_enabled] unless config_args[:hashtags_enabled].nil?
74
+ config[:hashtags][:top] = config_args[:hashtags_top] unless config_args[:hashtags_top].nil?
75
+ config[:hashtags][:notop] = config_args[:hashtags_notop] unless config_args[:hashtags_notop].nil?
76
+ config[:smileys][:enabled] = config_args[:smileys_enabled] unless config_args[:smileys_enabled].nil?
77
+ config[:smileys][:top] = config_args[:smileys_top] unless config_args[:smileys_top].nil?
78
+ config[:smileys][:notop] = config_args[:smileys_notop] unless config_args[:smileys_notop].nil?
79
+ config[:ignored_users] = config_args[:ignored_users] unless config_args[:ignored_users].nil?
80
+ config[:ignored_users].each do |user| user.downcase! end
81
+ config[:renamed_users].each do |old, new| new.downcase! end
82
+ config
83
+ end
84
+
85
+ private
86
+
87
+ # Symbolizes the keys of a hash, duh.
88
+ def symbolize_keys(hash)
89
+ hash.inject({}) do |result, (key, value)|
90
+ new_key = case key
91
+ when String then key.to_sym
92
+ else key
93
+ end
94
+ new_value = case value
95
+ when Hash then symbolize_keys(value)
96
+ else value
97
+ end
98
+ result[new_key] = new_value
99
+ result
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ # kate: indent-width 2
@@ -0,0 +1,43 @@
1
+ # defaults.rb - some constants
2
+ #
3
+ # This file is part of Empyrean
4
+ # Copyright (C) 2015 nilsding, pixeldesu
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ module Empyrean
20
+ # Application name
21
+ APP_NAME = "Empyrean"
22
+
23
+ # Version
24
+ VERSION = "0.1.0"
25
+
26
+ # Combined version string
27
+ VERSION_STR = "#{APP_NAME} #{VERSION}"
28
+
29
+ # Regexp for matching user names
30
+ USERNAME_REGEX = /[@]([a-zA-Z0-9_]{1,16})/
31
+
32
+ # Regexp for matching the client source
33
+ SOURCE_REGEX = /^<a href=\"(https?:\/\/\S+|erased_\d+)\" rel=\"nofollow\">(.+)<\/a>$/
34
+
35
+ # Regexp for matching hashtags
36
+ HASHTAG_REGEX = /[#]([^{}\[\]().,\-:!*_?#\s]+)/
37
+
38
+ # Path to the templates
39
+ TEMPLATE_DIR = File.expand_path "../templates", __FILE__
40
+
41
+ # The default template to use
42
+ DEFAULT_TEMPLATE = "default.html.erb"
43
+ end
@@ -0,0 +1,151 @@
1
+ # optparser.rb - parses CLI options using Ruby's OptionParser
2
+ #
3
+ # This file is part of Empyrean
4
+ # Copyright (C) 2015 nilsding, pixeldesu
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require 'optparse'
20
+ require 'ostruct'
21
+ require 'empyrean/defaults'
22
+ require 'empyrean/templatelister'
23
+
24
+ module Empyrean
25
+ class OptParser
26
+
27
+ def self.parse(args)
28
+ options = OpenStruct.new
29
+ options.jsondir = ""
30
+ options.outfile = "output.html"
31
+ options.config = File.expand_path('.', "config.yml")
32
+ options.config_values = {}
33
+ options.print_stats = false
34
+ options.template = DEFAULT_TEMPLATE
35
+ options.verbose = false
36
+
37
+ opts = OptionParser.new do |opts|
38
+ opts.banner = "Usage: stats.rb [options]"
39
+
40
+ opts.separator ""
41
+ opts.separator "Specific options:"
42
+
43
+ opts.on("-c", "--config CONFIG", "The configuration file to use (default: #{options.config})") do |config|
44
+ options.config = config
45
+ end
46
+
47
+ opts.on("-C", "--config-value KEY=VALUE", "Sets a configuration value (e.g. hashtags_enabled=false)") do |val|
48
+ key, value = val.split("=")
49
+ key = key.downcase
50
+ unless value.nil? # ignore empty values
51
+ case key.to_s
52
+ when /_enabled$/
53
+ value = to_bool value
54
+ when /_(no)?top$/, /timezone_difference$/
55
+ value = value.to_i
56
+ when /ignored_users/
57
+ value = value.split ','
58
+ end
59
+ options.config_values[key.to_sym] = value
60
+ end
61
+ end
62
+
63
+ opts.on("-g", "--generate-config CONFIG", "Generate a new configuration file") do |config_file|
64
+ fn = File.expand_path '.', config_file
65
+ if File.exist? fn
66
+ STDERR.puts "Cowardly refusing to overwrite already existing file #{config_file}."
67
+ exit 2
68
+ end
69
+ File.open fn, 'w' do |f|
70
+ f.write File.read File.expand_path("../../../config.yml.example", __FILE__)
71
+ STDERR.puts "Wrote new configuration to #{config_file}."
72
+ exit
73
+ end
74
+ end
75
+
76
+ opts.on("-d", "--jsondir DIRECTORY", "Directory with tweet files (containing 2014_07.js etc.)") do |dir|
77
+ dir = File.expand_path('.', dir)
78
+ unless File.exist?(dir) && File.directory?(dir)
79
+ STDERR.puts "not a directory: #{dir}"
80
+ exit 1
81
+ end
82
+
83
+ entries = Dir.entries(dir)
84
+ entries.each do |e|
85
+ # the file names of the tweet archive are in the format /^\d{4}_\d{2}\.js$/
86
+ unless e =~ /^\d{4}_\d{2}\.js$|\.+?/
87
+ STDERR.puts "not a tweets directory: #{dir}"
88
+ exit 1
89
+ end
90
+ end
91
+
92
+ options.jsondir = dir
93
+ end
94
+
95
+ opts.on("-o", "--outfile OUTFILE", "Output HTML file (default: #{options.outfile})") do |outfile|
96
+ options.outfile = outfile
97
+ end
98
+
99
+ opts.on("-l", "--list-templates", "List available templates") do
100
+ TemplateLister.print_list
101
+ exit
102
+ end
103
+
104
+ opts.on("-t", "--template TEMPLATE", "Template to use (default: #{options.template})") do |template|
105
+ options.template = template
106
+ end
107
+
108
+ opts.on("-p", "--[no-]print-stats", "Print stats to stdout") do |p|
109
+ options.print_stats = p
110
+ end
111
+
112
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
113
+ options.verbose = v
114
+ end
115
+
116
+ # No argument, shows at tail. This will print an options summary.
117
+ opts.on_tail("-h", "--help", "Show this message") do
118
+ puts opts
119
+ exit
120
+ end
121
+
122
+ # Another typical switch to print the version.
123
+ opts.on_tail("--version", "Show version") do
124
+ puts Empyrean::VERSION_STR
125
+ exit
126
+ end
127
+ end.parse!(args)
128
+
129
+ if options.jsondir.empty?
130
+ STDERR.puts "missing argument: --jsondir, see --help for more"
131
+ exit 1
132
+ end
133
+
134
+ options
135
+ end # parse()
136
+
137
+ private
138
+
139
+ ##
140
+ # "converts" a string to a boolean value
141
+ def self.to_bool str
142
+ if str == true || str =~ (/(true|t|yes|y|1)$/i)
143
+ true
144
+ else
145
+ false
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ # kate: indent-width 2
@@ -0,0 +1,35 @@
1
+ # templatelister.rb - lists available templates
2
+ #
3
+ # This file is part of Empyrean
4
+ # Copyright (C) 2015 nilsding, pixeldesu
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require 'empyrean/defaults'
20
+
21
+ module Empyrean
22
+ class TemplateLister
23
+ class << self
24
+ # Returns an array of available templates.
25
+ def list
26
+ Dir[File.join TEMPLATE_DIR, "*.html.erb"].map{ |t| File.basename t }
27
+ end
28
+
29
+ # Prints the available templates to stdout.
30
+ def print_list
31
+ puts list
32
+ end
33
+ end
34
+ end
35
+ end