ショートカットlink
import argparse
import socket
import sys
def get_local_ip():
"""自身のローカルIPアドレスを取得する"""
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect(('8.8.8.8', 80))
ip = s.getsockname()[0]
except Exception:
ip = '127.0.0.1'
finally:
s.close()
return ip
def main():
parser = argparse.ArgumentParser(description="ブラウザJSで疎通確認を行うリダイレクトHTMLを生成します。")
parser.add_argument("--output-html", default="index.html", help="出力するHTMLファイル名")
parser.add_argument("--protocol", default="http", help="プロトコル (デフォルト: http)")
parser.add_argument("--port", default="9250", help="ポート番号 (デフォルト: 9250)")
parser.add_argument("--urlpath", default="", help="URLのパス部分")
parser.add_argument("--title", default="アプリケーションショートカット",help="タイトル")
args = parser.parse_args()
# IPの取得とURLの組み立て
ip = get_local_ip()
path = args.urlpath if args.urlpath.startswith("/") or not args.urlpath else "/{0}".format(args.urlpath)
target_url = "{0}://{1}:{2}{3}".format(args.protocol, ip, args.port, args.urlpath)
# HTMLテンプレート (JavaScriptで疎通確認)
html_template = """<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{0}</title>
<style>
body {{ font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f4f4f9; }}
.card {{ background: white; padding: 2rem; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; max-width: 400px; }}
.spinner {{ border: 4px solid #f3f3f3; border-top: 4px solid #3498db; border-radius: 50%; width: 30px; height: 30px; animation: spin 1s linear infinite; margin: 10px auto; }}
@keyframes spin {{ 0% {{ transform: rotate(0deg); }} 100% {{ transform: rotate(360deg); }} }}
.error {{ color: #e74c3c; display: none; }}
a.urlLink {{ color: #3498db; text-decoration: none; font-weight: bold; }}
a.btnTag {{
position: relative;
display: inline-block;
padding: 0.5rem 4rem;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transition: all 0.3s;
transition: all 0.3s;
text-align: center;
vertical-align: middle;
text-decoration: none;
letter-spacing: 0.1em;
color: #212529;
border-radius: 0.5rem;
color: #fff;
background-color: #eb6100;
}}
a.btnTag:hover {{
color: #fff;
background: #f56500;
}}
</style>
</head>
<body>
<div class="card">
<div id="status-ui">
<h4>{0}</h4>
<p>疎通確認中...</p>
<div class="spinner"></div>
</div>
<div id="error-ui" class="error">
<h4>{0}</h4>
<p>接続に失敗しました...</p>
<p><a class="urlLink" href="{1}">{1}</a></p>
<a class="btnTag" href="#" onclick="location.reload()">再試行</a>
</div>
</div>
<script>
async function checkAndRedirect() {{
const url = "{1}";
const statusUi = document.getElementById('status-ui');
const errorUi = document.getElementById('error-ui');
console.log("[URL]:" + url);
try {{
// mode: 'no-cors' を指定することで、CORS設定がないサーバーでもを確認可能
await fetch(url, {{ mode: 'no-cors', cache: 'no-cache' }});
// 疎通できればリダイレクト
window.location.href = url;
}} catch (e) {{
// 失敗した場合(サーバー未起動、ネットワークエラー等)は表示変更
statusUi.style.display = 'none';
errorUi.style.display = 'block';
}}
}}
// 実行開始
checkAndRedirect();
</script>
</body>
</html>
"""
with open(args.output_html, "w", encoding="utf-8-sig") as f:
f.write(html_template.format(args.title, target_url))
if __name__ == "__main__":
main()