Github恶搞之自定义你的contribution图表
在正式写程序之前让我先来看看效果:
对了,这个程序的效果就是生成一个具有你想要的“contributions in the last year”图表的html页面。
当然,html文件,而不是你在Github上面个人主页中的实际的页面。
当然,你可以通过个人努力达到效果(我之前就见过一个I 心 U,但是暂时没有找到出处),不过那需要非常努力和耐性,并且那么做的话收获更多(如果不是仅仅为了那么做而commit+push的话),所以这里介绍一个程序来实现这种方法。
接下来我将用Java来编写程序,主要分为两个步骤:
- 下载网页源代码
- 根据自己设计的字体替换网页中对应的内容
其中第二步有很多现有的工具,比如Jsoup,但是可以用正则表达式直接解决,后来我发现一个写起来比较方便的方法,因为我发现每一种颜色对应一个fill元素,所以可以直接从fill元素下手。
我把设计的字体保存在了文件picture-fonts.txt(是一个只有字符"0"和"1"的字符文件)中,并把每个字符在picture-fonts.txt中的位置保存在了position.txt中。
他们的预期效果如下:
这意味着在这里你暂时只能达到“ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789”的效果。
“contributions in the last year”列表里面一共有7行53列,为了保(tou)险(lan)这里就先不去动最后一列了。所以我们有7行52列可以用,所以这个程序将会输出最多的我们想要的结果。
程序的代码就一个,内容如下:
package fungithub; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class FunGithub { private static Map<String, Word> wordMap = new HashMap<String, Word>(); private static int[][] picNumber = new int[1000][30]; public static void main(String[] args) { if (args.length != 2) { System.err.println("usage : <username> <words>"); System.exit(1); } solve(args[0], args[1]); } public static void solve(String username, String words) { words = words.toUpperCase(); try ( BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(System.getProperty("user.dir") + "/picture-fonts.txt"), "utf-8")) ) { int idx = 0; String line = null; while ((line = br.readLine()) != null) { line = line.trim(); if (line.length() == 0) continue; int len = line.length(); char[] ch = line.toCharArray(); for (int i = 0; i < len; i ++) { char c = ch[i]; picNumber[idx][i] = (int) c - (int)'0'; } idx ++; } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } try ( BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(System.getProperty("user.dir") + "/position.txt"), "utf-8")) ) { String line = null; while ((line = br.readLine()) != null) { line = line.trim(); if (line.length() == 0) continue; Word temp = new Word(line); wordMap.put(temp.getC(), temp); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } List<Integer> allWords = new ArrayList<Integer>(); int i; for (i = 0; i < words.length(); i ++) { String oneWordString = String.format("%c", words.charAt(i)); Word oneWord = wordMap.get(oneWordString); if (oneWord == null) { System.err.println(oneWordString + " not exists!"); continue; } List<Integer> tmpWordsList = oneWord.getWordsList(); if (allWords.size() + tmpWordsList.size() > 52 * 7) break; else { allWords.addAll(tmpWordsList); if (allWords.size() + 7 <= 52 * 7) for (int j = 0; j < 7; j ++) allWords.add(0); } } System.out.println("\"" + words.substring(0, i) +"\" solved!"); int delta = 52 * 7 - allWords.size(); for (int j = 0; j < delta; j ++) allWords.add(0); // allWords -- the list with 52 * 7 words generated. // download url content URL url = null; HttpURLConnection urlConnection = null; BufferedReader reader; String pageContent = ""; try { url = new URL("https://github.com/" + username); urlConnection = (HttpURLConnection) url.openConnection(); reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream(), "utf-8")); String line; while ((line = reader.readLine()) != null){ pageContent += line + "\n"; } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } pageContent = pageContent.replaceAll("fill=\"#[0-9a-e]{6}\"", "MoON1igHt"); for (int word : allWords) { String fillStr = null; if (word == 1) { fillStr = "fill=\"#1e6823\""; } else { double r = Math.random(); if (r <= 0.3) fillStr = "fill=\"#eeeeee\""; else if (r <= 0.9) fillStr = "fill=\"#d6e685\""; else if (r <= 0.96) fillStr = "fill=\"#8cc665\""; else fillStr = "fill=\"#44a340\""; } pageContent = pageContent.replaceFirst("MoON1igHt", fillStr); } pageContent = pageContent.replaceAll("MoON1igHt", "fill=\"#eeeeee\""); // write content to output html file, here I set it to Desktop, here I am the user "Administrator" on Windows7 String outputFileName = "C:/Users/Administrator/Desktop/" + username + "-" + words + ".html"; try ( OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(outputFileName), "utf-8"); ) { osw.write(pageContent); } catch (UnsupportedEncodingException | FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } System.out.println(username + "-" + words + ".html successifully generated at desktop!"); } static class Word { private String c; private int px; private int py; private int height; private int width; private List<Integer> wordsList; public Word(String line) { String[] arr = line.split(","); c = arr[0]; px = Integer.parseInt(arr[1]); py = Integer.parseInt(arr[2]); height = Integer.parseInt(arr[3]); width = Integer.parseInt(arr[4]); // generate wordsList wordsList = new ArrayList<Integer>(); for (int j = 0; j < width; j ++) for (int i = 0; i < height; i ++) wordsList.add(picNumber[px+i][py+j]); } public String getC() { return c; } public int getPx() { return px; } public int getPy() { return py; } public int getHeight() { return height; } public int getWidth() { return width; } public List<Integer> getWordsList() { return wordsList; } } }
另外还有2个资源文件,Github项目位置:https://github.com/moonlightpoet/FunGithub 有兴趣可以玩一下。
另外github pages上面放了两个可以看看在线效果(一个I Love you的和一个Fxxk you的):
注:今天找到了知乎上问题的出处了