メインコンテンツへスキップ

radiko APIを使って都道府県ごとのラジオ局一覧を出力する

require 'net/http'
require 'uri'
require 'rexml/document'

prefecture_names = {
  "1" => "北海道", "2" => "青森県", "3" => "岩手県", "4" => "宮城県", "5" => "秋田県",
  "6" => "山形県", "7" => "福島県", "8" => "茨城県", "9" => "栃木県", "10" => "群馬県",
  "11" => "埼玉県", "12" => "千葉県", "13" => "東京都", "14" => "神奈川県", "15" => "新潟県",
  "16" => "富山県", "17" => "石川県", "18" => "福井県", "19" => "山梨県", "20" => "長野県",
  "21" => "岐阜県", "22" => "静岡県", "23" => "愛知県", "24" => "三重県", "25" => "滋賀県",
  "26" => "京都府", "27" => "大阪府", "28" => "兵庫県", "29" => "奈良県", "30" => "和歌山県",
  "31" => "鳥取県", "32" => "島根県", "33" => "岡山県", "34" => "広島県", "35" => "山口県",
  "36" => "徳島県", "37" => "香川県", "38" => "愛媛県", "39" => "高知県", "40" => "福岡県",
  "41" => "佐賀県", "42" => "長崎県", "43" => "熊本県", "44" => "大分県", "45" => "宮崎県",
  "46" => "鹿児島県", "47" => "沖縄県"
}

prefectures = (1..47).map(&:to_s)

prefectures.each do |pref_code|
  url = "https://radiko.jp/v2/station/list/JP#{pref_code}.xml"
  uri = URI.parse(url)
  
  begin
    response = Net::HTTP.get_response(uri)
    if response.is_a?(Net::HTTPSuccess)
      document = REXML::Document.new(response.body)
      
      puts "## #{prefecture_names[pref_code]}(#{pref_code})"
      
      document.elements.each('stations/station') do |station|
        station_name = station.elements['name'].text
        station_id = station.elements['id'].text
        puts "- #{station_name}(#{station_id})"
      end
      puts "" 
    else
      puts "Failed to retrieve data for prefecture code #{pref_code}"
    end
  rescue => e
    puts "Error: #{e.message} for prefecture code #{pref_code}"
  end
end

北海道(1)
#

  • HBCラジオ(HBC)
  • STVラジオ(STV)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • AIR-G’(FM北海道)(AIR-G)
  • FM NORTH WAVE(NORTHWAVE)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(札幌)(JOIK)
  • NHK-FM(東京)(JOAK-FM)

青森県(2)
#

  • RAB青森放送(RAB)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム青森(AFB)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(仙台)(JOHK)
  • NHK-FM(東京)(JOAK-FM)

岩手県(3)
#

  • IBCラジオ(IBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム岩手(FMI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(仙台)(JOHK)
  • NHK-FM(東京)(JOAK-FM)

宮城県(4)
#

  • TBCラジオ(TBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • Date fm エフエム仙台(DATEFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(仙台)(JOHK)
  • NHK-FM(東京)(JOAK-FM)

秋田県(5)
#

  • ABSラジオ(ABS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム秋田(AFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(仙台)(JOHK)
  • NHK-FM(東京)(JOAK-FM)

山形県(6)
#

  • YBC山形放送(YBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • Rhythm Station エフエム山形(RFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(仙台)(JOHK)
  • NHK-FM(東京)(JOAK-FM)

福島県(7)
#

  • RFCラジオ福島(RFC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • ふくしまFM(FMF)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(仙台)(JOHK)
  • NHK-FM(東京)(JOAK-FM)

茨城県(8)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • LuckyFM 茨城放送(IBS)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

栃木県(9)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • CRT栃木放送(CRT)
  • RADIO BERRY(RADIOBERRY)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • LuckyFM 茨城放送(IBS)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

群馬県(10)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • FM GUNMA(FMGUNMA)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • LuckyFM 茨城放送(IBS)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

埼玉県(11)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • LuckyFM 茨城放送(IBS)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

千葉県(12)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • LuckyFM 茨城放送(IBS)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

東京都(13)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • LuckyFM 茨城放送(IBS)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

神奈川県(14)
#

  • TBSラジオ(TBS)
  • 文化放送(QRR)
  • ニッポン放送(LFR)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • interfm(INT)
  • TOKYO FM(FMT)
  • J-WAVE(FMJ)
  • ラジオ日本(JORF)
  • BAYFM78(BAYFM78)
  • NACK5(NACK5)
  • FMヨコハマ(YFM)
  • LuckyFM 茨城放送(IBS)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

新潟県(15)
#

  • BSNラジオ(BSN)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM NIIGATA(FMNIIGATA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

富山県(16)
#

  • KNBラジオ(KNB)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FMとやま(FMTOYAMA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

石川県(17)
#

  • MROラジオ(MRO)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム石川(HELLOFIVE)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

福井県(18)
#

  • FBCラジオ(FBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM福井(FMFUKUI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

山梨県(19)
#

  • YBSラジオ(YBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM FUJI(FM-FUJI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

長野県(20)
#

  • SBCラジオ(SBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM長野(FMN)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(東京)(JOAK)
  • NHK-FM(東京)(JOAK-FM)

岐阜県(21)
#

  • CBCラジオ(CBC)
  • TOKAI RADIO(TOKAIRADIO)
  • ぎふチャン(GBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • ZIP-FM(ZIP-FM)
  • FM GIFU(FMGIFU)
  • FM AICHI(FMAICHI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

静岡県(22)
#

  • SBSラジオ(SBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • K-MIX(K-MIX)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

愛知県(23)
#

  • CBCラジオ(CBC)
  • TOKAI RADIO(TOKAIRADIO)
  • ぎふチャン(GBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • ZIP-FM(ZIP-FM)
  • FM AICHI(FMAICHI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

三重県(24)
#

  • CBCラジオ(CBC)
  • TOKAI RADIO(TOKAIRADIO)
  • ぎふチャン(GBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • ZIP-FM(ZIP-FM)
  • レディオキューブ FM三重(FMMIE)
  • FM AICHI(FMAICHI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(名古屋)(JOCK)
  • NHK-FM(東京)(JOAK-FM)

滋賀県(25)
#

  • ABCラジオ(ABC)
  • MBSラジオ(MBS)
  • OBCラジオ大阪(OBC)
  • FM COCOLO(CCL)
  • FM802(802)
  • FM大阪(FMO)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • KBS京都ラジオ(KBS)
  • Kiss FM KOBE(KISSFMKOBE)
  • e-radio FM滋賀(E-RADIO)
  • ラジオ関西(CRK)
  • α-STATION FM KYOTO(ALPHA-STATION)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(大阪)(JOBK)
  • NHK-FM(東京)(JOAK-FM)

京都府(26)
#

  • ABCラジオ(ABC)
  • MBSラジオ(MBS)
  • OBCラジオ大阪(OBC)
  • FM COCOLO(CCL)
  • FM802(802)
  • FM大阪(FMO)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • KBS京都ラジオ(KBS)
  • Kiss FM KOBE(KISSFMKOBE)
  • α-STATION FM KYOTO(ALPHA-STATION)
  • ラジオ関西(CRK)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(大阪)(JOBK)
  • NHK-FM(東京)(JOAK-FM)

大阪府(27)
#

  • ABCラジオ(ABC)
  • MBSラジオ(MBS)
  • OBCラジオ大阪(OBC)
  • FM COCOLO(CCL)
  • FM802(802)
  • FM大阪(FMO)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • Kiss FM KOBE(KISSFMKOBE)
  • ラジオ関西(CRK)
  • KBS京都ラジオ(KBS)
  • α-STATION FM KYOTO(ALPHA-STATION)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(大阪)(JOBK)
  • NHK-FM(東京)(JOAK-FM)

兵庫県(28)
#

  • ABCラジオ(ABC)
  • MBSラジオ(MBS)
  • OBCラジオ大阪(OBC)
  • FM COCOLO(CCL)
  • FM802(802)
  • FM大阪(FMO)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • ラジオ関西(CRK)
  • Kiss FM KOBE(KISSFMKOBE)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(大阪)(JOBK)
  • NHK-FM(東京)(JOAK-FM)

奈良県(29)
#

  • ABCラジオ(ABC)
  • MBSラジオ(MBS)
  • OBCラジオ大阪(OBC)
  • FM COCOLO(CCL)
  • FM802(802)
  • FM大阪(FMO)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • Kiss FM KOBE(KISSFMKOBE)
  • ラジオ関西(CRK)
  • α-STATION FM KYOTO(ALPHA-STATION)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(大阪)(JOBK)
  • NHK-FM(東京)(JOAK-FM)

和歌山県(30)
#

  • ABCラジオ(ABC)
  • MBSラジオ(MBS)
  • OBCラジオ大阪(OBC)
  • FM COCOLO(CCL)
  • FM802(802)
  • FM大阪(FMO)
  • wbs和歌山放送(WBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • Kiss FM KOBE(KISSFMKOBE)
  • ラジオ関西(CRK)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(大阪)(JOBK)
  • NHK-FM(東京)(JOAK-FM)

鳥取県(31)
#

  • BSSラジオ(BSS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム山陰(FM-SANIN)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(広島)(JOFK)
  • NHK-FM(東京)(JOAK-FM)

島根県(32)
#

  • BSSラジオ(BSS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム山陰(FM-SANIN)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(広島)(JOFK)
  • NHK-FM(東京)(JOAK-FM)

岡山県(33)
#

  • RSKラジオ(RSK)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM岡山(FM-OKAYAMA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(広島)(JOFK)
  • NHK-FM(東京)(JOAK-FM)

広島県(34)
#

  • RCCラジオ(RCC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • 広島FM(HFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(広島)(JOFK)
  • NHK-FM(東京)(JOAK-FM)

山口県(35)
#

  • KRY山口放送(KRY)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム山口(FMY)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(広島)(JOFK)
  • NHK-FM(東京)(JOAK-FM)

徳島県(36)
#

  • JRT四国放送(JRT)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM徳島(FM807)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(松山)(JOZK)
  • NHK-FM(東京)(JOAK-FM)

香川県(37)
#

  • RNC西日本放送(RNC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム香川(FMKAGAWA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(松山)(JOZK)
  • NHK-FM(東京)(JOAK-FM)

愛媛県(38)
#

  • RNB南海放送(RNB)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM愛媛(JOEU-FM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(松山)(JOZK)
  • NHK-FM(東京)(JOAK-FM)

高知県(39)
#

  • RKC高知放送(RKC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム高知(HI-SIX)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(松山)(JOZK)
  • NHK-FM(東京)(JOAK-FM)

福岡県(40)
#

  • RKBラジオ(RKB)
  • KBCラジオ(KBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • LOVE FM(LOVEFM)
  • CROSS FM(CROSSFM)
  • FM FUKUOKA(FMFUKUOKA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

佐賀県(41)
#

  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム佐賀(FMS)
  • NBCラジオ(NBC)
  • RKBラジオ(RKB)
  • KBCラジオ(KBC)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

長崎県(42)
#

  • NBCラジオ(NBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM長崎(FMNAGASAKI)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

熊本県(43)
#

  • RKKラジオ(RKK)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FMKエフエム熊本(FMK)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

大分県(44)
#

  • OBSラジオ(OBS)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム大分(FM_OITA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

宮崎県(45)
#

  • 宮崎放送(MRT)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • エフエム宮崎(JOYFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

鹿児島県(46)
#

  • MBCラジオ(MBC)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • μFM(MYUFM)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

沖縄県(47)
#

  • RBCiラジオ(RBC)
  • ラジオ沖縄(ROK)
  • ラジオNIKKEI第1(RN1)
  • ラジオNIKKEI第2(RN2)
  • FM沖縄(FM_OKINAWA)
  • オーディオ高校野球(ABCR-KOSHIEN)
  • NHKラジオ第1(福岡)(JOLK)
  • NHK-FM(東京)(JOAK-FM)

関連記事

Kindleの蔵書一覧を生成するRubyスクリプト

MacにインストールされているKindleアプリのデータから蔵書一覧を生成 kindle_books_mac.rbrequire 'rexml/document' require 'date' require 'csv' # Kindle for Mac KINDLE_XML = "#{ENV['HOME']}/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/Cache/KindleSyncMetadataCache.xml" doc = REXML::Document.new(File.read(KINDLE_XML)) csv = CSV.generate(force_quotes: true) do |csv| doc.elements.each("//response/add_update_list/meta_data") do |e| csv << [ e.elements["ASIN"].text, e.elements["title"].text, e.elements["authors"].map{|item| item.text}.join('/'), e.elements["publishers"].map{|item| item.text}.join('/'), e.elements["publication_date"].text, e.elements["purchase_date"].text ] end end puts csv

Appleのヘルスケアデータから体重を抜き出してCSVファイルを作成する

Appleのヘルスケアアプリのデータを使って、他のアプリでグラフを描こうと思ったが、エクスポートされるデータはXMLのため、そのままでは扱いにくい。 このため、XMLファイルから体重データを抜き出してCSVを出力するRubyスクリプトを書いた。 require 'nokogiri' require 'date' reader = Nokogiri::XML::Reader File.read('export.xml') data = [] reader.each do |node| if node.name == 'Record' && node.attributes['type'] == 'HKQuantityTypeIdentifierBodyMass' d = Date.parse(node.attributes['startDate']).strftime("%Y-%m-%d") data << [d, node.attributes['value']] end end data.sort.each {|d| puts d.join(',') } =begin <Record type="HKQuantityTypeIdentifierBodyMass" sourceName="1byone Health" sourceVersion="63" device="&lt;&lt;HKDevice: 0x3013e9b30&gt;, name:iPhone, manufacturer:Apple, model:iPhone, hardware:iPhone, firmware:iPhone, software:17.5.1, localIdentifier:ja_JP, UDIDeviceIdentifier:ja_JP, creation date:2024-06-02 22:17:36 +0000&gt;" unit="kg" creationDate="2024-06-17 07:17:17 +0900" startDate="2024-06-17 07:17:17 +0900" endDate="2024-06-17 07:17:17 +0900" value="71.9"/> =end 以下、ChatGPTにヘルスケアデータの構造を聞いた回答 Appleのヘルスケアアプリでエクスポートされるデータは、XML (Extensible Markup Language) フォーマットで提供されます。このフォーマットは、ヘルスデータを構造化して格納するための標準的な形式です。 データの構造と内容 # XMLヘッダー エクスポートされたファイルは、XMLヘッダーから始まります。 <?xml version="1.0" encoding="UTF-8"?> 全体のルート要素 データ全体は <HealthData> というルート要素でラップされています。 <HealthData locale="en_US"> ... </HealthData> データの各エントリー ヘルスケアのデータは、それぞれの記録を <Record> 要素として格納します。主な属性は以下の通りです: type: データの種類(例: 歩数、心拍数など)。 sourceName: データのソース名(iPhone、Apple Watchなど)。 sourceVersion: ソースのバージョン情報。 unit: データの単位(例: count, bpm, kcal など)。 creationDate: データが作成された日時。 startDate: データの開始日時(測定期間の開始)。 endDate: データの終了日時(測定期間の終了)。 value: データの値(例: 歩数の数値、体重の値など)。 例:

RubyからBlueskyへの投稿

作成しているツールでRubyからBlueskyへ投稿したかったので、ShreyanJain9/bskyrb: Ruby Gem for interacting with BlueSky/AT Protocolというライブラリを使うことにした。 使用例を見ると、 require 'bskyrb' username = 'your_username' password = 'your_password' pds_url = 'https://bsky.social' credentials = Bskyrb::Credentials.new(username, password) session = Bskyrb::Session.new(credentials, pds_url) bsky = Bskyrb::RecordManager.new(session) post_uri = bsky.create_post("Hello world from bskyrb!")["uri"] bsky.like(post_uri) bsky.repost(post_uri) bsky.create_reply(post_uri, "Replying to post from bskyrb") とあり、一見簡単そうに見えるがBlueskyの場合はXやMastodonのAPIとは異なり、投稿するメッセージの中に、 URLがあってもリンクは設定されない ハッシュタグがあってもリンクは設定されない URLのコンテンツにOGBタグがあってもリンクカードは表示されない という仕様であり、なかなか面倒であることがわかった。 Ruby から Bluesky に投稿してみる Links, mentions, and rich text | Bluesky そんなわけで上記のドキュメントを参照しつつ、それぞれどうやれば良いのか調べてみた。 リンクの設定 # メッセージ中にURLがあれば、その部分を自動的にリンク設定したかったため、Rich text facetsの例にある以下の例を参考に、 { text: 'Go to this site', facets: [ { index: { byteStart: 6, byteEnd: 15 }, features: [{ $type: 'app.bsky.richtext.facet#link', uri: 'https://example.com' }] } ] } 以下のようなコードでfacetを作成した。 def create_facets_for_urls(text) facets = [] text_copy = text.dup URI.extract(text_copy, ['http', 'https']).each do |url| byte_start = text_copy[0, text_copy.index(url)].encode('UTF-8').bytesize byte_end = byte_start + url.bytesize facets << { 'index' => {'byteStart' => byte_start, 'byteEnd' => byte_end}, 'features' => [ { 'uri' => url, '$type' => 'app.bsky.richtext.facet#link', }, ], } text_copy[text_copy.index(url), url.length] = "\0" * url.length end facets end ハッシュタグの設定 # メッセージ中にハッシュタグがあれば、その部分を自動的にリンク設定したかったため、同じようなロジックでfacetを作成する。

radikoを録音してPoscastプレイヤーで再生する

miyagawaさんの以下のプログラムを組み合わせて使うことで、radikoで録音した番組をPodcastプレイヤーで再生することができる。 miyagawa/ripdiko: Rip radiko programs miyagawa/dircaster: Generate RSS 2.0 podcast out of directory with *.mp3s おおまかな流れは以下の感じ。 cronで起動されたripdikoがradikoを録音し、指定フォルダにMP3ファイルで保存する cronで起動したdircasterが指定フォルダにあるMP3ファイルを解析し、Podcast配信用のXMLを出力する Podcastプレイヤーで2で生成されるXMLを購読しておけば、番組が更新されるたびに通知され聞くことができる ただし、1のMP3ファイル、2のXMLはインターネットから参照できる場所に出力する必要がある(HTTPサーバが必要) Radikoプレミアムへの対応 # ただ、残念なことにripdikoはradikoプレミアムへは対応しておらず、エリアフリーで他県の番組を録音することができない。 このため、uru2/rec_radiko_ts: Radiko timefree program recorderを参考にして、radikoプレミアムへログインしエリアフリーで番組を録音できるようにした。 環境変数RIPDIKO_MAILでメールアドレス、RIPDIKO_PASSにパスワードを設定しておくことで、他県の番組も録音することができる。 diff --git a/bin/ripdiko b/bin/ripdiko index ebc756a..2ca3b70 100755 --- a/bin/ripdiko +++ b/bin/ripdiko @@ -8,6 +8,7 @@ require 'open-uri' require 'nokogiri' require 'date' require 'fileutils' +require 'json' module Notifier SCRIPTS = ENV['RIPDIKO_SCRIPTS'] || "#{ENV['HOME']}/.ripdiko/scripts" @@ -61,6 +62,43 @@ class DownloadTask @output = ENV['RIPDIKO_OUTPUT'] == nil ? "file" : ENV['RIPDIKO_OUTPUT'] end + def login + uri = URI.parse("https://radiko.jp/v4/api/member/login") + data = { + "mail" => ENV['RIPDIKO_MAIL'], + "pass" => ENV['RIPDIKO_PASS'] + } + + return "" if data["mail"].nil? || data["pass"].nil? + encoded_data = URI.encode_www_form(data) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = (uri.scheme == "https") + + request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/x-www-form-urlencoded'}) + request.body = encoded_data + response = http.request(request) + + return JSON.parse(response.body)["radiko_session"] || "" + end + + def logout + uri = URI.parse("https://radiko.jp/v4/api/member/logout") + data = { + "radiko_session" => @radiko_session + } + encoded_data = URI.encode_www_form(data) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = (uri.scheme == "https") + + request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/x-www-form-urlencoded'}) + request.body = encoded_data + response = http.request(request) + + @radiko_session = "" + end + + + def authenticate res = fetch 'https://radiko.jp/apps/js/playerCommon.js?_=20171113', {} if /new RadikoJSPlayer\(.*?'pc_html5',\s*'(\w+)'/ === res.body @@ -79,11 +117,16 @@ class DownloadTask abort "auth1 failed" end + @radiko_session = login + value = URI.encode_www_form_component(@radiko_session) + + auth2_url_param = @radiko_session.size > 0 ? "?radiko_session=#{value}" : "" + length = res['X-Radiko-KeyLength'].to_i offset = res['X-Radiko-KeyOffset'].to_i partial_key = Base64.strict_encode64(auth_key.byteslice(offset, length)) - res = fetch "https://radiko.jp/v2/api/auth2", + res = fetch "https://radiko.jp/v2/api/auth2#{auth2_url_param}", 'X-Radiko-User' => "dummy_user", 'X-Radiko-Device' => "pc", 'X-Radiko-Authtoken' => token, @@ -106,6 +149,40 @@ class DownloadTask def now_playing(station, area) now = Time.now + + station_list = { + "802" => "JP25", "ABC" => "JP25", "ABCR-KOSHIEN" => "JP1", "ABS" => "JP5", + "AFB" => "JP2", "AFM" => "JP5", "AIR-G" => "JP1", "ALPHA-STATION" => "JP25", + "BAYFM78" => "JP8", "BSN" => "JP15", "BSS" => "JP31", "CBC" => "JP21", + "CCL" => "JP25", "CRK" => "JP25", "CROSSFM" => "JP40", "CRT" => "JP9", + "DATEFM" => "JP4", "E-RADIO" => "JP25", "FBC" => "JP18", "FM-FUJI" => "JP19", + "FM-OKAYAMA" => "JP33", "FM-SANIN" => "JP31", "FM807" => "JP36", + "FMAICHI" => "JP21", "FMF" => "JP7", "FMFUKUI" => "JP18", "FMFUKUOKA" => "JP40", + "FMGIFU" => "JP21", "FMGUNMA" => "JP10", "FMI" => "JP3", "FMJ" => "JP8", + "FMK" => "JP43", "FMKAGAWA" => "JP37", "FMMIE" => "JP24", "FMN" => "JP20", + "FMNAGASAKI" => "JP42", "FMNIIGATA" => "JP15", "FMO" => "JP25", "FMS" => "JP41", + "FMT" => "JP8", "FMTOYAMA" => "JP16", "FMY" => "JP35", "FM_OITA" => "JP44", + "FM_OKINAWA" => "JP47", "GBS" => "JP21", "HBC" => "JP1", "HELLOFIVE" => "JP17", + "HFM" => "JP34", "HI-SIX" => "JP39", "IBC" => "JP3", "IBS" => "JP8", + "INT" => "JP8", "JOAK" => "JP8", "JOAK-FM" => "JP1", "JOBK" => "JP25", + "JOCK" => "JP16", "JOEU-FM" => "JP38", "JOFK" => "JP31", "JOHK" => "JP2", + "JOIK" => "JP1", "JOLK" => "JP40", "JORF" => "JP8", "JOYFM" => "JP45", + "JOZK" => "JP36", "JRT" => "JP36", "K-MIX" => "JP22", "KBC" => "JP40", + "KBS" => "JP25", "KISSFMKOBE" => "JP25", "KNB" => "JP16", "KRY" => "JP35", + "LFR" => "JP8", "LOVEFM" => "JP40", "MBC" => "JP46", "MBS" => "JP25", + "MRO" => "JP17", "MRT" => "JP45", "MYUFM" => "JP46", "NACK5" => "JP8", + "NBC" => "JP41", "NORTHWAVE" => "JP1", "OBC" => "JP25", "OBS" => "JP44", + "QRR" => "JP8", "RAB" => "JP2", "RADIOBERRY" => "JP9", "RBC" => "JP47", + "RCC" => "JP34", "RFC" => "JP7", "RFM" => "JP6", "RKB" => "JP40", + "RKC" => "JP39", "RKK" => "JP43", "RN1" => "JP1", "RN2" => "JP1", + "RNB" => "JP38", "RNC" => "JP37", "ROK" => "JP47", "RSK" => "JP33", + "SBC" => "JP20", "SBS" => "JP22", "STV" => "JP1", "TBC" => "JP4", + "TBS" => "JP8", "TOKAIRADIO" => "JP21", "WBS" => "JP30", "YBC" => "JP6", + "YBS" => "JP19", "YFM" => "JP8", "ZIP-FM" => "JP21" + } + # 都道府県コードの変換(自地域以外のラジオ局を指定された場合) + area = station_list[station] if station_list[station] != area + doc = Nokogiri::XML(URI.parse("https://radiko.jp/v3/program/now/#{area}.xml").open) node = doc.xpath(%Q|//station[@id="#{station}"]|).first @@ -209,6 +286,8 @@ class DownloadTask when "fifo" FileUtils.rm tempfile end + + logout end def fetch(url, headers)

Platypus - RubyスクリプトをMac OSのアプリに変換できるツール

sveinbjornt/Platypus: Create native Mac applications from command line scripts. スクリプト(Shellスクリプト、Perl、Python、Rubyなど)を標準のMac OS Xアプリケーション(.app)に変換するツール。 Platypusを使用すると、コマンドラインやターミナルを介さずに、スクリプトを直接実行可能なアプリケーションとして実行できる。 生成されるappのinfo.plistを編集することで、スクリプトをURLスキームに対応させることができる。 RubyではURLスキームで指定された文字列へARGVでアクセスできた。

OAuthでアクセストークンを取得するスクリプト

OAuthでアクセストークン、アクセストークンシークレットを取得するサンプル。毎回、同じようなスクリプトを書いて使い捨てにするのはムダなのでメモしておく。 ブラウザで表示されるURLへアクセスする リダイレクトされたURLのoauth_verifierの値を入力 access_token.token、access_token.secretが表示される require 'oauth' URL = "https://www.tumblr.com" consumer_key = 'Cls**********yaqV4' consumer_secret = 'RG****3KwFy' oauth = OAuth::Consumer.new(consumer_key, consumer_secret, site: URL) request = oauth.get_request_token(exclude_callback: true) puts "Access this URL: #{request.authorize_url}" print "oauth_verifier: " verifier = gets.chomp access_token = request.get_access_token(oauth_verifier: verifier) pp access_token