# <google>googleのサービス使ってブログもどき作ってみた

な〜んとなく、作ってみたよ
見切り発車で書いてるからまとまるか微妙だよ
いつものことですね
は〜い

目次

  1. 使ったもの
  2. 書いたコード
  3. できたもの
  4. その他

1.使ったもの

今回はgoogleのサービスだけを使ってブログっぽいものをどこまで作れるかをやろうということで、googleのサービスです

レイアウトの調整にbootstrapをちょっと使いました。

2.書いたコード

まずはgoogle formを用意します。
今回は暫定的に以下を聞きます。

  • ブログタイトル(必須)
  • ブログコンテンツ(必須)
  • 関連リンク(任意)

で、その結果をスプレに吐き出します。
オエ〜って感じですね(違う)
そうすることでスプレに吐き出されるのは聞いたこと+タイムスタンプになります

そのデータを基にしてブログぽい表示をしていきます

HTML

index.html

表示の基になるものです。特に何も書いてません

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>
  </head>
  <body>
    <h1>blog</h1>
    <?!= getcontent(); ?>
  </body>
</html>

さて、ここの

<?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?>

これはcssを読み出す用のやつです。  そして、

<?!= getcontent(); ?>

でコードを読みだします

css.html

google apps scriptを使うとcssもhtmlの中に書かなきゃいけません、難しいですね。

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<style>
.date{
  font-size:10px;
  font-weight:200;
}
.card{
  margin-bottom:30px;
  width:400px;
}
</style>

  特殊なことはないですね、bootsrap をCDNで引いてるくらいです

google apps script

htmlの表示

単純なhtmlの表示にもスクリプトが必要です。

function doGet() {
  return HtmlService.createTemplateFromFile("index").evaluate();
}

これはコピペのようなものです。

sheetの情報からブログっぽく表示する

html内から呼び出したコードです

function getcontent() {
  //変数spreadsheetに指定のスプレッドシートオブジェクトを取得します
  var url ="ここにシートのリンク";
  var spreadsheet = SpreadsheetApp.openByUrl(url);

  //spreadsheetのシートを全て読み出す
  var sheets = spreadsheet.getSheets();
  //結果の格納されたシートを読み出す
  var sheet = sheets[0];

  //シートの最終行番号、最終列番号を取得
  var startrow = 1;
  var startcol = 1;
  var lastrow = sheet.getLastRow();
  var lastcol = sheet.getLastColumn();

  //シートのデータを取得
  var sheetdata = sheet.getSheetValues(startrow, startcol, lastrow, lastcol);

  //シートをhtmlコードに反映していく
  var content="";
  for(var i=lastrow-1;i>=1;i--){
    content+="<div class=\"card\">";
    content+="<div class=\"card-header\"><p class=\"card-subtitle date\">"+sheetdata[i][0]+"</p>";
    content+="<h2 class=\"card-title\">"+sheetdata[i][1]+"</h2></div>";
    content+="<p>"+sheetdata[i][2]+"</p>";
    //link適応
    if(sheetdata[i][3]!=""){
      if(sheetdata[i][3].indexOf(",")!=-1){
        var links=sheetdata[i][3].split(",");
        for(var j=0;j<links.length;j++){
          content+="<a href=\""+links[j]+"\">"+links[j]+"</a>";
        }
      }else{
        content+="<a href=\""+sheetdata[i][3]+"\">"+sheetdata[i][3]+"</a>";
      }
    } 
    content+="</div>"
  }
  return content
}

こんな感じです
シートの回答を読みだして、新しい順に表示するようにしてます。
逆順表示にして、最新の回答から順にカード表示してます。
リンク情報を別で取ってるのはリンクタグ適応のためです。
これでカード表示でいい感じのができます

3.できたもの

こんな感じのができます

f:id:poolbooyer:20190805002327p:plain
作成した画面

改造タイム入ったのでリンクは死んでます

PCからぱらっとみるぶんには問題ないとこまできました。
どうしてもトップにgoogle公認のものではないことを示すあれが出るので、ガチブログとして運用するには向かないかも?

4.その他

参考サイト

tonari-it.com

上記ページ以外にもgas全般で参考にしてます

getbootstrap.com

# <chrome extension>次の動画を通知してくれる拡張作った

思いつきから作りました はい。

目次

  1. 作ったもの
  2. 実際のコード
  3. 動作確認の方法
  4. 公開、リリースまでの流れ

1.作ったもの

今回はchromeyoutubeを自動再生中に次の動画タイトルを通知してくれる拡張を作りました。
ターゲットとしてはyoutubeをバックグラウンドで再生して作業する人ですかね。

f:id:poolbooyer:20190707233557p:plain
作成した拡張機能(画像内赤枠)

2.実際のコード

そもそもchrome extensionって何使って作るだって感じあるじゃないですか、少なくとも僕にはありました。
調べたじゃないですか
なんと、なぁんとですねぇ、

というかJSONがキモでそれに関連して機能に応じてhtml,CSS,JSを使うって感じです。
なんかいけそうな気がしませんか。
僕はあんまりそんな気がしなかったのでサンプルを改造して目的のものを完成させました。

今回参考にしたサンプル
Water Popup

これをベースにしてググりながらごりごりやりました
今回やりたいことを踏まえて必要なコードはJSON,JS,HTMLでした

2.1 JSON

今回のキモのJSONからです。
この、拡張機能を機能させるときに必ず必要になるのがmanifest.jsonというものです。
どういう拡張機能かを表すファイルですね。
拡張機能の名称とかを書いていきます。
以下のような感じです。

{
  "name": "Next Movie is...",
  "description": "バックグラウンドで再生してるそのyoutube、次に流れる映像を通知します!",
  "version": "1.0.1",
  "manifest_version": 2,
  "permissions": ["tabs","https://www.youtube.com/*", "notifications"],
  "background": {
    "presitent": true,
    "page":"popup.html"
  },
  "icons": {
    "16": "icons/icon_16.png",
    "32": "icons/icon_32.png",
    "48": "icons/icon_48.png",
    "128": "icons/icon_128.png"
  }
}

詳しい記法は書きませんがざっくりした説明

name value
name 拡張機能
description 拡張機能の説明
manifest_version 書式のバージョン(基本的に2)
permissions 拡張機能がアクセスすることのできる権限
background 拡張機能がバックグラウンドで動くのを許可するやつ(くらいに思ってる)
icons 拡張機能のアイコン

2.2HTML

すごいよ、びっくりするよ、見ちゃう??見ちゃう?????

<script src="background.js"></script>

だけ、やば、終わり

2.3JavaScript

今後修正が多少入りそうなので公開されてる状態というよりは最低限こんな感じで動くよってコードを載せときます。
まずはトリガーまわり

//tabが読み込まれた(更新された時のトリガー)
chrome.tabs.onUpdated.addListener(function(tabId, props,tab) {
  //読み込み状態の判別
  if (props.status != "complete"){
    //タブのタイトル、urlを取得
    var ttl=tab.title;
    var url=tab.url;
    //動画再生画面の時に通知を発生
    if(url.match(/watch/)!=null){
      //動画名称の部分を抜き出し
      ttl=ttl.slice(0,-10);
      //通知を出す関数にタイトルを渡す
      send_notification(ttl);
    }
  }
});

読み込み状態の判別については何度か試したのですが、==にして実行すると前に再生していた動画が出てきてたので今回はこれでいきます。
からの通知生成

function send_notification(ttl) {
  
  chrome.notifications.create({
    //通知のタイプ
    type:     'basic',
    //通知につけるアイコン
    iconUrl:  'icons/icon_32.png',
    //通知のタイトル
    title:    'Next Movie is',
    //通知の内容(動画タイトル)
    message:  ttl,
    priority: 0
  });
}

こんな感じのコードを実装すると目的の機能ができました。

3.動作確認の方法

まずはchromeを起動して
more tools->extensionsを開きます
開いたらdeveloper ModeをONにします。
そうすると"Load unpacked","pack extension","update"が出てきます。
その中で、"load unpacked" を開いて、マニフェストファイルのあるフォルダを選択します。
そうすると拡張機能が読み込まれます。

f:id:poolbooyer:20190708011723p:plain
読み込んだ拡張機能
これにエラーやらなんやらが全部出ます。
これは個人的になのですが"update"を使っても変わらないことがあったのでコード変えたらdelete->"Load unpacked"がいいと思います。

4.公開、リリースまでの流れ

今回はなんとなく、webストアにリリースしてみました。
そこまでの流れをまとめます。
まずは登録します。
webストアにアクセスしてデベロッパダッシュボードを開きます。

f:id:poolbooyer:20190708012754p:plain
デベロッパダッシュボードの場所
で登録をぽちぽちします。
で5$って言われるので
f:id:poolbooyer:20190708012915p:plain
支払いを求める表示
ぽちぽち支払います。
f:id:poolbooyer:20190708012943p:plain
支払い後の表示
そして、新しいアイテムを追加を押して追加します。
ここで追加できるのは、作成したコードが格納されたフォルダをZIPしたものです。
f:id:poolbooyer:20190708013734p:plain
アップロード画面
アップロードしたら、ストアの情報を追加していきます。
ここで色々画像が必要になります。
必要な画像のざっくりした一覧です。

画像の種類 サイズ
アイコン 128x128
タイル(小) 440x280
タイル(大) 920x680
マーキー 1400x560

それをアップロードして、関連したフォームを埋めていくとプレビュー機能を使ってストア画面に表示した感じをみれるようになります。
そんな感じでぽちぽちして公開を押すと公開されます。
時間はちょっとかかります。我慢です。
我慢し続けると、ページができます。

f:id:poolbooyer:20190708015708p:plain
完成したストアページ
ちなみに今回リリースした拡張機能は以下リンクから

chrome.google.com

今後更新されたらまた書きます。


2019/07/10 リポジトリ公開しました

github.com

<ruby> grep ぽいことするやつ作った

新しいMac買ってしまった
お金やばいのも多少あるけどそれ以上にサクサク動いて快適

grepぽいことするやつ作った

grepってコマンドあるじゃないですか。
ファイルの中身とか検索するあれ
あれってwindowsで使えないじゃないですか
互換はあるけど使い方で見れば別物なのでなんともっていう

そこで同じように使うとなったらプログラム書くしかなくねとなり書きました。

目次

  1. 今回の目的
  2. 作ったもの
    2.1 ファイルの取得
    2.2 取得したファイルの検索
    2.3 検索結果の出力
    3.できたもの

1.今回の目的

目的はほぼ最初のところに書いてしまっている。
なのでさらに詳細まで書きます。
今回の最終的な目的としてはドラッグ&ドロップで対象ファイル選んでキーワード、条件に一致するやつを検索するようなものを完成させるのが目的になっています。
最初っから一気に完成形を目指せる自信は皆無なのでまずはコマンドで使えるようになればいいかなということで作成します。
今回のゴールとしては

grep-test poolbooyer$ grep -n index data/* 
data/sample1.txt:3:index
data/sample1.txt:4:index
data/sample1.txt:5:index 
data/sample1.txt:6:/index.htm
data/sample1.txt:7:index
data/sample1.txt:9:/index.html
data/sample1.txt:10:/index.htm
data/sample2.txt:3:/assets/js/index.js
...

的なものを作ります。
ただ、このままだと微妙に見づらさがあるので、出力形式を以下のようにします。

file名
行数:ヒットした文字列
行数:ヒットした文字列
file名
行数:ヒットした文字列
...

なんかいい感じに同じファイル単位でまとめて表示するようにします。

2.作ったもの

 ということで実装していきました。
今回の流れとしては

ファイル一覧取得->ファイル内容取得->ファイル内部検索->結果出力

でいきます。
この時検索する語句と対象はコマンドライン引数で引っ張ってきます。

ruby serch-eg.rb フォルダ名 検索語句

最初二つはDirで取得して、fileopenなので今回は
ちゃんと書きます

2.1 ファイルの取得

まずはファイルの情報を取得します。
検索対象のフォルダの中身を確認します。
その後、検索対象の中身を取得します。
今回はファイル名とファイルの中身を1つの配列で返すようにしました。
まずはフォルダの中身の確認と取得するところを呼び出すところまで

# 引数のフォルダの中身を確認する
fi=Dir::entries(ARGV[0])
  # 結果を取扱う配列
  data=[]
  # フォルダ中身全てに対して
  for i in 0..(fi.length-1) do
    if fi[i].length>2 then
      # ファイルの中身を呼び出して配列に追加
      data.push(read_file(ARGV[0]+fi[i]))
    end
  end

read_fileに渡しているARGV[0]+fi[i]はファイルへのパスです

その上で読み出すプログラム

def read_file(path)
  r_data=[]
  r_data[0]=path
  File.open(path,"r") do |f|
    r_data[1]=f.read
  end
  # 読み込んだデータとファイルのパスを返す
  return r_data
end

的な感じです

2.2 ファイルの検索

読み込んだ情報をもとにしてその中身を検索します。

targetには読み込んだデータ、queryには検索する文字列が入っています。

def search_infile(target,query)
  # 検索結果
  res=[] 
  for i in 0..(target.length-1) do
    # 文字列を含むか検索
    if target[i].include?(query) then
      res[i]=true
    else
      res[i]=false
    end
  end
  # 検索結果を返す
  return res
end

2.3 結果の出力

 検索と出力が1つのプログラムにまとめてます。
ここは分割する予定です。
検索するプログラムにコマンドライン引数で受け取った検索文字列と読み込んだファイルのデータを渡すところから

  query=ARGV[1]
  search_each(data,query)

そして、2.2のプログラムを呼び出します

def search_each(data,query)
  data.each do |line|
    # line[1]にあるファイルの中身を改行単位で配列に分割
    target=line[1].split("\n")
    # 検索結果を取得
    res=search_infile(target,query)
    # 検索結果をカウント
    count=0

    # ファイル名称を出力
    puts line[0]
    #  検索結果を参照
    for i in 0..(res.length-1) do
      # 一致していたら出力
      if res[i]==true then
        puts "L#{i+1}: #{target[i]}"
      else
        count+=1
      end
    end
    # 1つも一致しなかったら"Not found"と出力
    if count==(res.length) then
      puts "Not found"
    end
    # ファイルの結果の間に一行あける
    puts ""
  end
end

3.できたもの

ということでこれを実行するとこんな感じになります

grep-test poolbooyer$ ruby ./searcher/search-eg.rb data/ inde
data/sample4.txt
L1: index
L2: /index.htm
L3: index
L7: index
L8: /assets/js/index.js
L9: index
L10: /index.html

data/sample5.txt
L1: inde
...

grep-test poolbooyer$ ruby ./searcher/search-eg.rb data/ fuga
data/sample4.txt
Not found

data/sample5.txt
Not found

data/sample1.txt
...

これで期待する結果の出方になりましたー!
ちなみに今回のコードは以下にあります

github.com (search/に入ってます、検索対象にするデータはscript/generator.rbを使って生成してます)
まだ直しが入る予定なので今回はここまで