@oquno@x.oq.la

ブログです oq.la/++

Pokémon Trading Card Game Pocket

https://www.pokemontcgpocket.com/ja/

多分ポケモンカード世代ではあるんだけど、金払ってカード集めるの好きではないので全くやってこなかったしゲームボーイのは出た頃にやったことあったような気がするくらいで、今回のは課金しないでもできるっぽいので始めてみました。割と早めに飽きる気もするが…。

https://oquno.com/log/eid4210.html

この靴がまたぼろぼろになりがちだったので、今週くらいから、買ってあった同タイプの革靴に履き替えてみている。そしたら当然のごとく靴擦れが発生し、踵に痛み&皮の破れが。仕組み的にはぴったりでない靴を履いてるのが悪いってことなんだろうか。でも本当にぴったりだと履くのも脱ぐのも困難だしただ硬いのが悪いんじゃないかと思ってるけど、靴替える度に靴擦れにやられたくない…。ということでスニーカーが人気な理由にようやく気付いた。

gyazo

前から欲しかったのだけど、JavaScript書きたくなさすぎて遠のいていたのをChatGPTに厳しく指導をすることで実現できた。

https://x.oq.la/js/flickrembed.js

WriteFreelyはヘッダに投稿ボタンとかあってこのツールの位置固定しづらいので、(ボタンだけ)ドラッグできるようにしたのがわからせポイントです。まだいじる気がするけど、これをロードすればすべてのテキストエリアにFlickr埋め込み放題になる(はず)。サムネイルクリックするとembedコードとかがテキストエリアに入る。パクリ元ははてなブログのFlickr埋め込み機能です。Flickr無料プランの使い勝手悪くなってるので現在はあんま使われてなさそうな気はしている。あと合わせてGyazo埋め込みグリモンも書かせてみた

https://gist.github.com/oquno/2419d0ad137b8db208a8da232cf5f567

正直あんまり興味はないのだけれど、後年読み返したときにこんな時期だったなと思い出せる方が良いので何でも書いておこうという気持ちで書く。とはいっても特に感想というほどのものもなく。大体投票日前に見える時代になったので特に驚きもなく、京都はさらに驚きのないエリアでしたね。京都でいうと今回もバランスよく各党がバラけて議席を獲得しているものの特に接戦もなくおもしろみはなかった。市長選とか府知事選は開票時に事務所に行く気にもなるのだけれど、国政選挙だとあんまノらないですね。

Super G Timbuk2 Parkside Backpack

なんかウェアラブルデバイスについての調査(NDAとかなかったので書く)に協力して、Google TV Streamer買うクーポンでももらおうかと思ってたら専用ショップから選ぶスタイルだったのでカバンをもらうことにした。なんかショップの通常ラインナップにはなかったアイテムなので転売とかすればGoogle TV Streamer買える気がするけど面倒だしちょうどリュックほしいところでもあったので、使おうかという気持ち。

花柄ランタン×アイアムアイ

花柄ランタンのチャンスを最近逃してたのでアイアムアイとのツーマンで摂取。新曲もいい感じだった。犬の歌は犬の歌プレイリスト(柴田聡子、超右腕、ゆ~すほすてる、いおかゆうみなどを想定)作りたくなる感じだった。 アイアムアイもホームすぎてかきあげろ!をみんな最初からできてしまっていたりと良かった。

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

仙台在住の秘密のコペカチータとザ・チャンス(大阪支店)の初陣を見る機会はここしかないので、リリースパーティーへ。一人で座っての弾き語りしか見てないけれど、今回は総勢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]
}