Raspberry Piでプレゼンテーションシステムを構築

あけましておめでとうございます🙇🙇🙇．
この記事は　[Muroran Institute of Technology Advent Calendar 2018](https://adventar.org/calendars/3589) 5日目の記事です．
もう年も越しましたが，ガキ使が終わるまでが期限ということで…

今回は，研究室のゼミ向けにセットアップした Raspberry Pi を紹介します．

## 背景
私が所属する研究室では，毎月 2 研究室合同で mtg をやっていますが，人数が多いため時間の削減のため，事前に全員のスライドを PDF で集め，一台のパソコンでスクリーンに表示しています．
流れとしては，全員が研究室の GitLab に PDF をアップロード（プッシュ）します．
GitLab CI の機能により，ある決められた時刻になると，プログラムが走り1つの PDF に集約されます．

今までは，その PDF をダウンロードし，スクリーンに写していましたが，私自身のメイン PC でその作業をしていたため，「気になったことが検索できない」，「メモをPCで取れない」といった悩みがありました．
タブレットでスクリーンに出していた時もありましたが，ページ送りが煩雑であり，ノート PC を mtg に 2 台持って行こうかと思いましたが，重くなるので今回はその悩みを Raspberry Pi で解決しようというわけです．

## 準備

[【ヘッドレス】Raspberry Pi 3 セットアップ for macOS](https://qiita.com/y_k/items/2e37583d4a5dcf81dc19) を参考にRaspberry Piをインストールする．

その後 evince と python3 をインストールしてください．

## 流れ
電源を入れると同時にスクリプトが走り，GitLab から CI で生成された PDF を zip 形式でダウンロードします．
その zip ファイルを Python で解凍し，evince を `--presentation` オプションで起動します．
自動実行は `~/.config/lxsession/LXDE/autostart` で実現しました．

## スクリプト
<details>
<summary>**クリックでプログラム全文を展開します**</summary>
<div>

```python3
#!/usr/bin/env python3

import os, sys
import yaml
import json
import requests
from requests.exceptions import Timeout
import subprocess
import zipfile

def get_jobs(config, project_id):
  headers = {'PRIVATE-TOKEN': config['gitlab_token']}
  url = 'http://gitlab.dslabo.net/api/v4/projects/{}/jobs?scope[]=success'.format(project_id)
  r = requests.get(url, headers=headers, timeout=(6.0, 15.0))
  return json.loads(r.text)

def download_zip(config, url):
  headers = {'PRIVATE-TOKEN': config['gitlab_token']}
  r = requests.get(url, headers=headers, timeout=(6.0, 15.0))
  with open('/home/pi/scripts/files/download.zip', 'wb') as f:
    f.write(r.content)
  with zipfile.ZipFile('/home/pi/scripts/files/download.zip') as f:
    f.extractall('/home/pi/scripts/files')

def main():
  with open('/home/pi/scripts/config.yml') as f:
    config = yaml.load(f)

  try:
    zip_url = ''
    for i in get_jobs(config, 130):
      if i['name'] == 'release_pdflatex':
        zip_url = "{}/{}".format(i['web_url'], 'artifacts/download')
        with open('/home/pi/scripts/filename.txt', 'w') as f:
          f.write(i['ref'])
        break

    if zip_url != '':
      download_zip(config, zip_url)
  except Timeout:
    pass

  filename = ''
  with open('/home/pi/scripts/filename.txt', 'r') as f:
    filename = f.readline()

  if os.path.exists("/home/pi/scripts/files/{}.pdf".format(filename)):
    res = subprocess.run(["evince", "--presentation", "/home/pi/scripts/files/{}.pdf".format(filename)], stdout=subprocess.PIPE)
    sys.stdout.buffer.write(res.stdout)

if __name__ == '__main__':
  main()
```

</div>

## 今後の課題
私の研究室では提出がギリギリの人やついついファイル名が規則通りになっていなかったり，あるいはディレクトリを間違えたりとトラブルがあり（午前に mtg のため修正の時間もない）， mtg 中の提出が横行しているので，それに対応する必要があります．

お付き合いいただきありがとうございました🙇

## 参考
* [Qiita: python上でunixコマンドを実行する](https://qiita.com/tdrk/items/9b23ad6a58ac4032bb3b)
* [note.nkmk.me: Pythonでzipファイルを圧縮・解凍するzipfile](https://note.nkmk.me/python-zipfile/)
* [たつこの部屋: ubuntu で root 時に cannot open display となる件](http://d.hatena.ne.jp/jimbeam0203/20090815/1250305365)
* [Cosnomi Blog: 【Python】requestsを使うときは必ずtimeoutを設定するべき](https://blog.cosnomi.com/archives/1259)