Alt+PでAmazon・楽天・Yahoo!・ヨドバシ・ビックカメラのリンクと合計金額=本体価格+送料を計算し、標準プロンプト窓に表示|Tampermonkey
// ==UserScript==
// @name Total Price Format to Prompt (Alt+P)
// @namespace http://tampermonkey.net/
// @version 10.1
// @description Alt+PでAmazon・楽天・Yahoo!・ヨドバシ・ビックカメラの合計金額とリンクを計算し、標準プロンプト窓に表示
// @match https://www.amazon.co.jp/*
// @match https://*.rakuten.co.jp/*
// @match https://*.yahoo.co.jp/*
// @match https://www.yodobashi.com/*
// @match https://www.biccamera.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
document.addEventListener('keydown', function(event) {
// Alt + P の判定
if (event.altKey && !event.ctrlKey && !event.shiftKey && (event.key === 'p' || event.key === 'P' || event.code === 'KeyP')) {
event.preventDefault();
var d = document, u = location.href, t = d.title;
var priceNum = 0;
var shippingNum = 0;
var displayPriceStr = '価格不明';
function parseNum(str) {
return str ? Number(String(str).replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) - 0xFEE0)).replace(/[^\d]/g, '')) || 0 : 0;
}
// ==========================================
// 1. Amazon の処理
// ==========================================
if (u.includes('amazon.co.jp')) {
var eA = d.querySelector('#corePrice_feature_div .a-price .a-offscreen') ||
d.querySelector('#priceblock_ourprice') ||
d.querySelector('#priceblock_dealprice') ||
d.querySelector('.a-price .a-offscreen');
if (eA) priceNum = parseNum(eA.textContent);
var deliveryEl = d.querySelector('[data-csa-c-delivery-price]');
if (deliveryEl) {
shippingNum = parseNum(deliveryEl.getAttribute('data-csa-c-delivery-price'));
} else {
var shipElA = d.querySelector('#ourprice_shippingmessage') || d.querySelector('#delivery-message') || d.querySelector('[id*="shipping"]');
var shipTextA = shipElA ? shipElA.textContent : d.body.innerText;
if (shipTextA.includes('無料配送') || shipTextA.includes('Prime') || shipTextA.includes('プライム')) {
shippingNum = 0;
} else {
var mA = shipTextA.match(/配送料[^0-90-9]*([0-90-9,]+)円/);
if (mA) {
shippingNum = parseNum(mA[1]);
} else {
var mA2 = shipTextA.match(/¥\s*([0-90-9,]+)/);
if (mA2) shippingNum = parseNum(mA2[1]);
}
}
}
t = t.replace(/^Amazon\s*\|\s*/, '');
}
// ==========================================
// 2. 楽天市場 の処理
// ==========================================
else if (u.includes('rakuten.co.jp')) {
let jsonParsed = false;
try {
const appDataEl = d.getElementById('item-page-app-data');
if (appDataEl) {
const jsonData = JSON.parse(appDataEl.textContent);
const skuInfo = jsonData.api?.itemInfoSku || jsonData.newApi?.itemInfoSku;
if (skuInfo) {
if (skuInfo.taxIncludedPrice) {
priceNum = Number(skuInfo.taxIncludedPrice);
jsonParsed = true;
}
if (skuInfo.shipping && skuInfo.shipping.postageIncluded) {
shippingNum = 0;
}
}
}
} catch(err) {}
if (!jsonParsed || priceNum === 0) {
var priceElR = d.querySelector('meta[property="product:price:amount"]') || d.querySelector('meta[itemprop="price"]');
if (priceElR) priceNum = parseNum(priceElR.getAttribute('content'));
}
if (shippingNum === 0) {
var shipElR = d.querySelector('[class*="postage"]') || d.querySelector('[class*="shipping"]') || d.querySelector('.price_delivery');
var shipTextR = shipElR ? shipElR.textContent : '';
if (shipTextR.includes('送料無料') || shipTextR.includes('送料込み')) {
shippingNum = 0;
} else {
var matchR = shipTextR.match(/([0-90-9,]+)\s*円/);
if (matchR) {
shippingNum = parseNum(matchR[1]);
} else {
var bodyMatchR = d.body.innerText.match(/送料\s*[::]?\s*([0-90-9,]+)円/);
if (bodyMatchR) shippingNum = parseNum(bodyMatchR[1]);
}
}
}
}
// ==========================================
// 3. Yahoo!ショッピング の処理
// ==========================================
else if (u.includes('yahoo.co.jp')) {
t = t.replace(/\s*[:\-]\s*(Yahoo!ショッピング|通販).*$/i, '');
var mp = d.querySelector('meta[property="product:price:amount"]') || d.querySelector('meta[itemprop="price"]');
if (mp) priceNum = parseNum(mp.getAttribute('content') || mp.textContent);
for (var sc of d.getElementsByTagName('script')) {
var tx = sc.textContent;
if (tx.includes('postageData') || tx.includes('taxIncludedPrice')) {
if (!priceNum) {
let m = tx.match(/"taxIncludedPrice"\s*:\s*(\d+)/);
if (m) priceNum = Number(m[1]);
}
if (tx.includes('"isPostageFree":true')) {
shippingNum = 0;
} else {
let m = tx.match(/"fee"\s*:\s*(\d+)/);
if (m) shippingNum = Number(m[1]);
}
}
}
if (shippingNum === 0 && d.body.innerText.includes('送料無料')) {
shippingNum = 0;
} else if (shippingNum === 0) {
let m = d.body.innerText.match(/送料[^0-90-9]*([0-90-9,]+)円/);
if (m) shippingNum = parseNum(m[1]);
}
}
// ==========================================
// 4. ヨドバシカメラ の処理
// ==========================================
else if (u.includes('yodobashi.com')) {
t = t.normalize('NFC').replace(/ヨドバシ\.com - (.*?) 通販【全品無料配達】/g, '$1');
var priceElY = d.querySelector('.js_ppSalesPrice') || d.querySelector('meta[property="product:price:amount"]') || d.querySelector('meta[itemprop="price"]');
if (priceElY) {
priceNum = parseNum(priceElY.getAttribute('content') || priceElY.textContent);
}
if (d.body.innerText.includes('全品配達料金無料') || d.body.innerText.includes('送料無料')) {
shippingNum = 0;
} else {
let m = d.body.innerText.match(/送料[^0-90-9]*([0-90-9,]+)円/);
if (m) shippingNum = parseNum(m[1]);
}
}
// ==========================================
// 5. ビックカメラ の処理(強化版)
// ==========================================
else if (u.includes('biccamera.com')) {
// タイトル整形(ビックカメラ.com - などを削除)
t = t.normalize('NFC').replace(/^ビックカメラ\.com\s*-\s*/, '');
// 価格の取得 ([itemprop="price"] またはメタタグ)
var priceElB = d.querySelector('[itemprop="price"]') || d.querySelector('meta[property="product:price:amount"]');
if (priceElB) {
priceNum = parseNum(priceElB.getAttribute('content') || priceElB.textContent);
}
// 送料の取得(DOM要素またはページ全体から「送料〇〇円」を柔軟に検索)
var bodyText = d.body.innerText;
// 「送料無料」が明示されている場合
if (bodyText.includes('送料無料') && !bodyText.match(/送料\s*[1-90-9]/)) {
shippingNum = 0;
} else {
// 「送料550円」などのパターンを正規表現で厳密に抽出(改行やスペースを許容)
var matchShipping = bodyText.match(/送料\s*([0-90-9,]+)\s*円/);
if (matchShipping) {
shippingNum = parseNum(matchShipping[1]);
} else {
shippingNum = 0; // 見つからない場合は0円(または基本無料)として扱う
}
}
}
// 合計金額の組み立て
if (priceNum > 0) {
var totalNum = priceNum + shippingNum;
displayPriceStr = totalNum.toLocaleString() + '円=' + priceNum.toLocaleString() + '+' + shippingNum.toLocaleString();
}
var l = '■<a href="' + u + '" target="_blank" rel="nofollow">【' + displayPriceStr + '】' + t + '</a><br>';
// 標準プロンプト窓で表示(Enterキーで閉じられます)
prompt('HTML', l);
// クリップボードへのコピーも並行して試みる
navigator.clipboard.writeText(l).catch(function(err) {});
}
});
})();
Alt+PでAmazon・楽天・Yahoo!・ヨドバシのリンクと合計金額=本体価格+送料を計算し、標準プロンプト窓に表示|Tampermonkey
// ==UserScript==
// @name Total Price Format to Prompt (Alt+P)
// @namespace http://tampermonkey.net/
// @version 9.0
// @description Alt+PでAmazon・楽天・Yahoo!・ヨドバシの合計金額とリンクを計算し、標準プロンプト窓に表示
// @match https://www.amazon.co.jp/*
// @match https://*.rakuten.co.jp/*
// @match https://*.yahoo.co.jp/*
// @match https://www.yodobashi.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
document.addEventListener('keydown', function(event) {
// Alt + P の判定
if (event.altKey && !event.ctrlKey && !event.shiftKey && (event.key === 'p' || event.key === 'P' || event.code === 'KeyP')) {
event.preventDefault();
var d = document, u = location.href, t = d.title;
var priceNum = 0;
var shippingNum = 0;
var displayPriceStr = '価格不明';
function parseNum(str) {
return str ? Number(String(str).replace(/[0-9]/g, c => String.fromCharCode(c.charCodeAt(0) - 0xFEE0)).replace(/[^\d]/g, '')) || 0 : 0;
}
// ==========================================
// 1. Amazon の処理
// ==========================================
if (u.includes('amazon.co.jp')) {
var eA = d.querySelector('#corePrice_feature_div .a-price .a-offscreen') ||
d.querySelector('#priceblock_ourprice') ||
d.querySelector('#priceblock_dealprice') ||
d.querySelector('.a-price .a-offscreen');
if (eA) priceNum = parseNum(eA.textContent);
var deliveryEl = d.querySelector('[data-csa-c-delivery-price]');
if (deliveryEl) {
shippingNum = parseNum(deliveryEl.getAttribute('data-csa-c-delivery-price'));
} else {
var shipElA = d.querySelector('#ourprice_shippingmessage') || d.querySelector('#delivery-message') || d.querySelector('[id*="shipping"]');
var shipTextA = shipElA ? shipElA.textContent : d.body.innerText;
if (shipTextA.includes('無料配送') || shipTextA.includes('Prime') || shipTextA.includes('プライム')) {
shippingNum = 0;
} else {
var mA = shipTextA.match(/配送料[^0-90-9]*([0-90-9,]+)円/);
if (mA) {
shippingNum = parseNum(mA[1]);
} else {
var mA2 = shipTextA.match(/¥\s*([0-90-9,]+)/);
if (mA2) shippingNum = parseNum(mA2[1]);
}
}
}
t = t.replace(/^Amazon\s*\|\s*/, '');
}
// ==========================================
// 2. 楽天市場 の処理
// ==========================================
else if (u.includes('rakuten.co.jp')) {
let jsonParsed = false;
try {
const appDataEl = d.getElementById('item-page-app-data');
if (appDataEl) {
const jsonData = JSON.parse(appDataEl.textContent);
const skuInfo = jsonData.api?.itemInfoSku || jsonData.newApi?.itemInfoSku;
if (skuInfo) {
if (skuInfo.taxIncludedPrice) {
priceNum = Number(skuInfo.taxIncludedPrice);
jsonParsed = true;
}
if (skuInfo.shipping && skuInfo.shipping.postageIncluded) {
shippingNum = 0;
}
}
}
} catch(err) {}
if (!jsonParsed || priceNum === 0) {
var priceElR = d.querySelector('meta[property="product:price:amount"]') || d.querySelector('meta[itemprop="price"]');
if (priceElR) priceNum = parseNum(priceElR.getAttribute('content'));
}
if (shippingNum === 0) {
var shipElR = d.querySelector('[class*="postage"]') || d.querySelector('[class*="shipping"]') || d.querySelector('.price_delivery');
var shipTextR = shipElR ? shipElR.textContent : '';
if (shipTextR.includes('送料無料') || shipTextR.includes('送料込み')) {
shippingNum = 0;
} else {
var matchR = shipTextR.match(/([0-90-9,]+)\s*円/);
if (matchR) {
shippingNum = parseNum(matchR[1]);
} else {
var bodyMatchR = d.body.innerText.match(/送料\s*[::]?\s*([0-90-9,]+)円/);
if (bodyMatchR) shippingNum = parseNum(bodyMatchR[1]);
}
}
}
}
// ==========================================
// 3. Yahoo!ショッピング の処理
// ==========================================
else if (u.includes('yahoo.co.jp')) {
t = t.replace(/\s*[:\-]\s*(Yahoo!ショッピング|通販).*$/i, '');
var mp = d.querySelector('meta[property="product:price:amount"]') || d.querySelector('meta[itemprop="price"]');
if (mp) priceNum = parseNum(mp.getAttribute('content') || mp.textContent);
for (var sc of d.getElementsByTagName('script')) {
var tx = sc.textContent;
if (tx.includes('postageData') || tx.includes('taxIncludedPrice')) {
if (!priceNum) {
let m = tx.match(/"taxIncludedPrice"\s*:\s*(\d+)/);
if (m) priceNum = Number(m[1]);
}
if (tx.includes('"isPostageFree":true')) {
shippingNum = 0;
} else {
let m = tx.match(/"fee"\s*:\s*(\d+)/);
if (m) shippingNum = Number(m[1]);
}
}
}
if (shippingNum === 0 && d.body.innerText.includes('送料無料')) {
shippingNum = 0;
} else if (shippingNum === 0) {
let m = d.body.innerText.match(/送料[^0-90-9]*([0-90-9,]+)円/);
if (m) shippingNum = parseNum(m[1]);
}
}
// ==========================================
// 4. ヨドバシカメラ の処理
// ==========================================
else if (u.includes('yodobashi.com')) {
// ヨドバシ特有のタイトル整形(通販表記などを削除)
t = t.normalize('NFC').replace(/ヨドバシ\.com - (.*?) 通販【全品無料配達】/g, '$1');
var priceElY = d.querySelector('.js_ppSalesPrice') || d.querySelector('meta[property="product:price:amount"]') || d.querySelector('meta[itemprop="price"]');
if (priceElY) {
priceNum = parseNum(priceElY.getAttribute('content') || priceElY.textContent);
}
// ヨドバシは全品基本送料無料(またはページ内で判定)
if (d.body.innerText.includes('全品配達料金無料') || d.body.innerText.includes('送料無料')) {
shippingNum = 0;
} else {
let m = d.body.innerText.match(/送料[^0-90-9]*([0-90-9,]+)円/);
if (m) shippingNum = parseNum(m[1]);
}
}
// 合計金額の組み立て
if (priceNum > 0) {
var totalNum = priceNum + shippingNum;
displayPriceStr = totalNum.toLocaleString() + '円=' + priceNum.toLocaleString() + '+' + shippingNum.toLocaleString();
}
var l = '■<a href="' + u + '" target="_blank" rel="nofollow">【' + displayPriceStr + '】' + t + '</a><br>';
// 標準プロンプト窓で表示(Enterキーで閉じられます)
prompt('HTML', l);
// クリップボードへのコピーも並行して試みる
navigator.clipboard.writeText(l).catch(function(err) {});
}
});
})();
- WindowsでAutoHotkeyを使用する場合は、‘AutoHotkey.ahk’へのショートカットを
C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startupに登録しておくと、起動時にAutoHotkeyを起動して常駐させておくことができる。
- AutoHotkeyは’AutoHotkey.ahk’というファイル名、かつ、‘UTF-8(BOM付き)’、かつ、改行コード’CR+LF’のテキストファイルとして作る(以下の文字列をそのファイルにコピペすればよい)。
- 以下のコードでは、Windows用キーボードの[アプリケーションキー(メニューキー)]を二度押しするとBraveのTampermonkeyを介して、任意のウェブページのリンクコードがクリップボードに得られるようになる。
#Requires AutoHotkey v2.0
#UseHook ; UseHookをOnにした状態で使用
AppsKey::
{
key := "AppsKey"
ErrorLevel := !KeyWait(key, "T0.3")
If (ErrorLevel) { ; 長押しした場合:MIFES
Run('C:\Program Files\MIFES11\MIW.exe')
KeyWait(key)
return
}
ErrorLevel := !KeyWait(key, "D, T0.2")
If (!ErrorLevel) { ; 2度押しした場合:【旧:短押しの処理】Ctrl+. や GG 送信など
Send("!p") ; Alt+P を送信 (確実に戻すためにシンプルに記述)
Sleep(300) ; 待て
A_Clipboard := ""
Send("^a")
Sleep(50)
Send("^c")
if ClipWait(0.5) {
Send("{Enter}")
}
KeyWait(key)
return
} else { ; 短押しした場合:【旧:2度押しの処理】Alt+C 送信など
Send("!c") ; Alt+C を送信 (確実に戻すためにシンプルに記述)
Sleep(300) ; ポップアップの表示を待つ
; クリップボードを一旦空にしてからコピーを試みる
A_Clipboard := ""
Send("^a") ; 全選択
Sleep(50)
Send("^c") ; コピー
; クリップボードにデータが入ったか少し待つ(最大0.5秒)
if ClipWait(0.5) {
Send("{Enter}")
}
KeyWait(key)
return
}
}