@oquno@x.oq.la

ブログです oq.la/++

秘密のコペカチータとザ・チャンス(大阪支店) 秘密のコペカチータとザ・チャンス(大阪支店)

仙台在住の秘密のコペカチータとザ・チャンス(大阪支店)の初陣を見る機会はここしかないので、リリースパーティーへ。一人で座っての弾き語りしか見てないけれど、今回は総勢11人(?)あおいさんはスナックのママバージョンということでギターは持たず、マイク&たまにタンバリンでステージ上の移動も可能なスタイル。このままいけば秘密のコペカチータの時代来ると思います。

ひょうへんクラブは初めてだったけど信頼と実績のメンバーで、バンドいいなあという感じの良さだった。外も繋がりを感じさせる出演者陣で良い構成のリリパだった。

ひょうへんクラブ

BalatroのPlayストア版1500円ということで、SteamゲームはそのままAndroidで遊べるわけではなく別なので、モバイル課金の習慣のない自分としては渋っていたのけれど、定額課金とかで貯まったPlayポイントをPlayストアクレジットに変換して体感数百円に圧縮してごまかして買った。

というのも週末に電車移動の時間を潰したいという気持ちが高まったため。モバイル版は欲を言えば縦画面で遊びたいけど、ドラッグ?スワイプ?の選択UIが実装されててタッチで十分遊べるようになってた。というかモバイル版あればSteam版もSwitch版もいらない気がする(Switch版は買ってないけど)。

水平線✕てら✕Ribet townsがまた見れるぞということで神戸へ。神戸久々。Ribet townsは意外と初神戸とのこと。先週のMINAMI WHEELに引き続きの水平線と同じく先週に引き続きのRibet townsと、久しぶりになってしまったてら君のスタイルの違うグッドミュージック3者という感じでよかった。

水平線 てら(band set) Ribet towns

あと帰りGoogle Mapsに騙されて電車変なのに乗ってしまったけど終電じゃなかったのでなんとかリカバリーできた。神戸はこういうスリルがある。

EPGStation to Google Calendar

というのをGoogle Apps Scriptでやってみた。 これを定期的に実行すればGoogle Calendarで録画済番組が見れて便利かもしれないという試み。予約のカレンダーもあると便利かもしれない。

function updateEpgstation() {
  var baseUrl = "https://epgstation.example.com";
  var calId = "YOUR_CALENDAR_ID";
  // BASIC 認証の場合
  var account = "dankogai:kogaidan";
  var calendar = CalendarApp.getCalendarById(calId);
  var apiUrl = baseUrl + '/api/recorded?isHalfWidth=true';
  var res = UrlFetchApp.fetch(apiUrl, {
    'method': 'get',
    'headers': {
      'Authorization': Utilities.base64Encode(account),
    }}
  );
  var reserves = JSON.parse(res.getContentText());
  var events = [];
  reserves.records.forEach(function(record) {
    var event = {};
    event.title = record.name;
    event.start = new Date(record.startAt);
    event.end = new Date(record.endAt);
    event.description = record.description + "\n" + record.extended + 
      "\n" + baseUrl + "/#/recorded/detail/" + record.id;
    events.push(event);
  });
  mergeAndUpdate(calendar, events);
}

// カレンダーの既存の予定にマージ
function mergeAndUpdate(calendar, newSchedules) {
  var range = getScheduleRange(newSchedules)
  Logger.log("range: "+ range[0] + "~" + range[1])
  var currentEvents = calendar.getEvents(range[0], range[1])
  var dontAdd = []
  var done = []
  currentEvents.forEach(function(event){
    var line = event.getStartTime().getTime() + event.getTitle()
    if (done.indexOf(line) > -1)
    {
      Logger.log("delete duplicate event" + event.getTitle())
      event.deleteEvent()
      return
    }
    done.push(line)

    var exists = false
    newSchedules.forEach(function(schedule){
      if (
        schedule.start.getTime() < new Date(2010, 1, 1).getTime() ||
        schedule.title == event.getTitle() &&
        schedule.start.getTime() == event.getStartTime().getTime() &&
        schedule.end.getTime() == event.getEndTime().getTime() &&
        schedule.description.length == event.getDescription().length/* &&
        schedule.location == event.getLocation()*/)
      {
        if (dontAdd.indexOf(schedule) > -1)
        {
          Logger.log("duplicate " + schedule.title)
          event.deleteEvent()
        }
        else
        {
          dontAdd.push(schedule)
          Logger.log("already created " + schedule.title)
        }
        exists = true
        return
      }
    })
    if (!exists && event.getStartTime().getTime() > range[0].getTime())
    {
      Logger.log("delete " + event.getTitle())
      event.deleteEvent()
    }
  });
  // 新しいスケジュールを追加
  newSchedules.forEach(function(schedule){
    if (schedule != null && dontAdd.indexOf(schedule) < 0)
    {
      Logger.log("create " + schedule.title)
      if ("allDay" in schedule && schedule.allDay)
      {
        var createAllDay = calendar.createAllDayEvent(schedule.title, schedule.start,
          { description: schedule.description, location: schedule.location})
      }
      else
      {
        var created = calendar.createEvent(schedule.title,
          schedule.start, schedule.end, { description: schedule.description, location: schedule.location})
      }
      Utilities.sleep(100)
    }
  });
}

// どの期間のカレンダー予定を取得すればいいかを判定
function getScheduleRange(schedules) {
  var start
  var end
  schedules.forEach(function(schedule){
    if (start == null || schedule.start < start)
    {
      start = schedule.start
    }
    if (end == null || end < schedule.end)
    {
      end = schedule.end
    }
  })
  return [start, end]
}

Ribet towns

月曜日はRibet towns を見にMINAMI WHEELを抜けて。最近野外とか銭湯とかで見がちだったけど、久々にライブハウスで音に包まれてよかった。7年ぶりのFireloopということでした。

イベント自体は最後までいれなかったけど、Fireloopあたりまた足を伸ばしたい。

3日目は少年キッズボウイ、ハク。、Sawa Angstromを軸に見て、合間にRibet towns見に行くという姿勢。

少年キッズボウイやっぱいいなあというのと横一列のマイクスタンドでバレーボウイズをまた想起する。Sawa Angstromは昨年振りになってしまったけれど、Clapperの照明とかもゴリゴリに合わせてだいぶグルーヴ感高まり良かった。ハク。はもうガツッと売れてしまっていいのではないか。個人的にはベースのカノさんの演奏中の表情の変化とかがいいですね。

書いておく。

(夜と)SAMPO以外はそこまで目当てなかったのでヌルっと見た。 意外と良かったのは、ゴッドタンでちらっと見たくらいの記憶の柏木ひなたが、アウェイ感のあるサーキットだから明日のワンマンで初披露のつもりだったけどやったるわという決意でやった新曲Alcaが良かった。曲が合ってると言うのもあると思うけど。

Meilisearch with Serene Bach

移転前のブログにもMeilisearchで検索できるようにしました。もともとSerene Bachに検索ページはあってMySQLで普通に検索した結果返すやつで正直個人ブログならそれで十分ではあるのだけれど、同じ感じにした。

ただ、旧ブログはさくらVPSで動かしてて、CORSとか考えるの面倒でMeilisearchをさくらVPSでも動かすのにしょぼいプラン(メモリ1GB)だとメモリがカツカツに近づいてくるのでそろそろ撤退して自宅サーバーに一本化するのもいいかなと思ったり安定性がまだなあと思ったり。

PXL_20241009_020813110

https://x.oq.la/nintendo-switchnobatsuteripeng-zhang-shitexiu-li-he

こちらから9日に返ってきた。バッテリー交換は作業費に含むけど外装は別途500円というお手頃価格。さすが天下の任天堂はんやということでこのままSwitch 2までがんばります。

PXL_20241012_112314460

今年も3daysパスということで、初日からまあまあ見た。なかなか関西で見る機会なさそうな名誉伝説をちゃんと見れたのが良かった。曲と声が良いのだけど、ライブで見たラヴィングはライブでバンドの演奏で聴くとこうなのか!という完成度を見せつけられた。あとは何から始めようかとあんま人気なのに初見で行きなくないなという気持ちで見た娯楽という神戸のバンドまあまあよかった。あとはSummer Whalesの関西最後の姿を見たり(そんなMCもなかったけれど…)。安定の水平線を見たりホーム感あるSubway Daydreamを見たり。