-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit ff61ac1
Showing
1 changed file
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,360 @@ | ||
<!DOCTYPE html> | ||
<html lang="ja"> | ||
|
||
<head> | ||
<meta charset="UTF-8"> | ||
<title>researchmap 論文リストダウンロードツール</title> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/encoding.min.js"></script> | ||
<style> | ||
.container { | ||
max-width: 800px; | ||
margin: 0 auto; | ||
padding: 20px; | ||
font-size: 16px; | ||
} | ||
|
||
h1 { | ||
font-size: 28px; | ||
margin-bottom: 1em; | ||
} | ||
|
||
.description { | ||
margin-bottom: 2em; | ||
line-height: 1.6; | ||
color: #333; | ||
} | ||
|
||
.description ol { | ||
margin-left: 1.5em; | ||
padding-left: 0; | ||
} | ||
|
||
.description li { | ||
margin-bottom: 0.5em; | ||
} | ||
|
||
.input-form { | ||
margin-bottom: 2em; | ||
font-size: 18px; | ||
} | ||
|
||
.input-form input { | ||
width: 80%; | ||
padding: 12px; | ||
margin-right: 10px; | ||
font-size: 18px; | ||
border: 2px solid #ccc; | ||
border-radius: 4px; | ||
} | ||
|
||
.input-form button { | ||
padding: 12px 24px; | ||
font-size: 18px; | ||
background-color: #4CAF50; | ||
color: white; | ||
border: none; | ||
border-radius: 4px; | ||
cursor: pointer; | ||
} | ||
|
||
.input-form button:hover { | ||
background-color: #45a049; | ||
} | ||
|
||
.paper { | ||
margin-bottom: 1em; | ||
padding: 1em; | ||
border-bottom: 1px solid #eee; | ||
font-size: 16px; | ||
} | ||
|
||
.title { | ||
font-weight: bold; | ||
} | ||
|
||
.authors { | ||
color: #666; | ||
margin: 0.5em 0; | ||
} | ||
|
||
.journal { | ||
font-style: italic; | ||
} | ||
|
||
.error { | ||
color: red; | ||
margin: 1em 0; | ||
} | ||
|
||
.download-buttons { | ||
margin: 1em 0; | ||
display: none; | ||
} | ||
|
||
.download-buttons button { | ||
padding: 8px 16px; | ||
margin-right: 10px; | ||
font-size: 16px; | ||
background-color: #2196F3; | ||
color: white; | ||
border: none; | ||
border-radius: 4px; | ||
cursor: pointer; | ||
} | ||
|
||
.download-buttons button:hover { | ||
background-color: #1976D2; | ||
} | ||
</style> | ||
</head> | ||
|
||
<body> | ||
<div class="container"> | ||
<h1>researchmap 論文リストダウンロードツール</h1> | ||
<div class="description"> | ||
<p>このツールは、researchmapの論文リストを様々な形式でダウンロードするためのものです。</p> | ||
<p>使い方:</p> | ||
<ol> | ||
<li>researchmapのプロフィールURL(例:https://researchmap.jp/ユーザーID)を入力</li> | ||
<li>「表示」ボタンをクリックして論文リストを表示</li> | ||
<li>必要な形式(Word、CSV、LaTeX)を選んでダウンロード</li> | ||
</ol> | ||
</div> | ||
<div class="input-form"> | ||
<input type="text" id="urlInput" placeholder="https://researchmap.jp/ユーザーID"> | ||
<button onclick="handleSubmit()">表示</button> | ||
</div> | ||
<div class="download-buttons" id="downloadButtons"> | ||
<button onclick="downloadAs('text')">TEXT形式</button> | ||
<button onclick="downloadAs('word')">Word形式</button> | ||
<button onclick="downloadAs('csv')">CSV形式</button> | ||
</div> | ||
<div id="papers"></div> | ||
</div> | ||
|
||
<script> | ||
let currentPapers = []; // 現在表示中の論文データを保持 | ||
|
||
function extractUserId(url) { | ||
try { | ||
const urlObj = new URL(url); | ||
const path = urlObj.pathname; | ||
const userId = path.split('/').filter(p => p).pop(); | ||
return userId; | ||
} catch (error) { | ||
console.error('URLの解析に失敗:', error); | ||
return null; | ||
} | ||
} | ||
|
||
async function fetchPapers(userId) { | ||
try { | ||
const response = await fetch(`https://api.researchmap.jp/${userId}/published_papers`); | ||
if (!response.ok) { | ||
throw new Error('APIの呼び出しに失敗しました'); | ||
} | ||
const data = await response.json(); | ||
const papers = data.items || []; | ||
displayPapers(papers); | ||
} catch (error) { | ||
console.error('エラー:', error); | ||
document.getElementById('papers').innerHTML = | ||
`<p class="error">論文データの取得に失敗しました。${error.message}</p>`; | ||
} | ||
} | ||
|
||
function displayPapers(papers) { | ||
currentPapers = papers; // データを保存 | ||
const container = document.getElementById('papers'); | ||
if (papers.length === 0) { | ||
container.innerHTML = '<p>論文データが見つかりませんでした。</p>'; | ||
document.getElementById('downloadButtons').style.display = 'none'; | ||
return; | ||
} | ||
|
||
container.innerHTML = ''; | ||
papers.forEach(paper => { | ||
const paperDiv = document.createElement('div'); | ||
paperDiv.className = 'paper'; | ||
|
||
const title = paper.paper_title?.ja || paper.paper_title?.en || ''; | ||
const authors = paper.authors?.ja || paper.authors?.en || []; | ||
const authorNames = authors.map(author => author.name).join(', '); | ||
const journalName = paper.publication_name?.ja || paper.publication_name?.en || ''; | ||
const doi = paper.identifiers?.doi?.[0] || ''; | ||
|
||
paperDiv.innerHTML = ` | ||
<div class="title">${title}</div> | ||
<div class="authors">${authorNames}</div> | ||
<div class="journal">${journalName} ${paper.publication_date || ''}</div> | ||
${doi ? `<div class="doi">DOI: ${doi}</div>` : ''} | ||
`; | ||
|
||
container.appendChild(paperDiv); | ||
}); | ||
|
||
// ダウンロードボタンを表示 | ||
document.getElementById('downloadButtons').style.display = 'block'; | ||
} | ||
|
||
function handleSubmit() { | ||
const url = document.getElementById('urlInput').value.trim(); | ||
if (!url) { | ||
document.getElementById('papers').innerHTML = | ||
'<p class="error">URLを入力してください。</p>'; | ||
return; | ||
} | ||
|
||
const userId = extractUserId(url); | ||
if (!userId) { | ||
document.getElementById('papers').innerHTML = | ||
'<p class="error">URLからユーザーIDを抽出できませんでした。</p>'; | ||
return; | ||
} | ||
|
||
fetchPapers(userId); | ||
} | ||
|
||
function downloadAs(format) { | ||
if (currentPapers.length === 0) return; | ||
|
||
let content = ''; | ||
const filename = `papers.${getFileExtension(format)}`; | ||
|
||
switch (format) { | ||
case 'text': | ||
content = generateTextContent(currentPapers); | ||
break; | ||
case 'word': | ||
content = generateHTMLContent(currentPapers, format); | ||
break; | ||
case 'csv': { | ||
const csvContent = generateCSVContent(currentPapers); | ||
// SJISエンコーディングに変換 | ||
const unicodeArray = Encoding.stringToCode(csvContent); | ||
const sjisArray = Encoding.convert(unicodeArray, 'SJIS', 'UNICODE'); | ||
content = new Uint8Array(sjisArray); | ||
break; | ||
} | ||
} | ||
|
||
const blob = new Blob([content], { type: getMimeType(format) }); | ||
const url = URL.createObjectURL(blob); | ||
const a = document.createElement('a'); | ||
a.href = url; | ||
a.download = filename; | ||
document.body.appendChild(a); | ||
a.click(); | ||
document.body.removeChild(a); | ||
URL.revokeObjectURL(url); | ||
} | ||
|
||
function getFileExtension(format) { | ||
switch (format) { | ||
case 'text': return 'txt'; | ||
case 'word': return 'doc'; | ||
case 'csv': return 'csv'; | ||
} | ||
} | ||
|
||
function getMimeType(format) { | ||
switch (format) { | ||
case 'text': | ||
return 'text/plain'; | ||
case 'word': | ||
return 'text/html'; | ||
case 'csv': | ||
return 'text/csv'; | ||
} | ||
} | ||
|
||
function generateHTMLContent(papers, format) { | ||
return `<!DOCTYPE html> | ||
<html lang="ja"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>論文リスト</title> | ||
<style> | ||
body { font-family: "MS Mincho", serif; line-height: 1.5; } | ||
.paper { margin-bottom: 1em; } | ||
.title { font-weight: bold; } | ||
.authors { color: #000; } | ||
</style> | ||
</head> | ||
<body> | ||
<h1>論文リスト</h1> | ||
${papers.map(paper => { | ||
const title = paper.paper_title?.ja || paper.paper_title?.en || ''; | ||
const authors = (paper.authors?.ja || paper.authors?.en || []) | ||
.map(author => author.name).join(', '); | ||
const journal = paper.publication_name?.ja || paper.publication_name?.en || ''; | ||
const date = paper.publication_date || ''; | ||
const doi = paper.identifiers?.doi?.[0] || ''; | ||
return `<div class="paper"> | ||
<div class="title">${escapeHTML(title)}</div> | ||
<div class="authors">${escapeHTML(authors)}</div> | ||
<div class="journal">${escapeHTML(journal)} ${date}</div> | ||
${doi ? `<div class="doi">DOI: ${doi}</div>` : ''} | ||
</div>`; | ||
}).join('\n')} | ||
</body> | ||
</html>`; | ||
} | ||
|
||
function escapeHTML(str) { | ||
return str | ||
.replace(/&/g, '&') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, '''); | ||
} | ||
|
||
function generateCSVContent(papers) { | ||
const header = '"Title","Authors","Journal","Date","DOI"\n'; | ||
const rows = papers.map(paper => { | ||
const title = paper.paper_title?.ja || paper.paper_title?.en || ''; | ||
const authors = (paper.authors?.ja || paper.authors?.en || []) | ||
.map(author => author.name).join('; '); | ||
const journal = paper.publication_name?.ja || paper.publication_name?.en || ''; | ||
const date = paper.publication_date || ''; | ||
const doi = paper.identifiers?.doi?.[0] || ''; | ||
return `"${escapeCSV(title)}","${escapeCSV(authors)}","${escapeCSV(journal)}","${date}","${doi}"`; | ||
}).join('\n'); | ||
return header + rows; | ||
} | ||
|
||
function generateTextContent(papers) { | ||
return papers.map(paper => { | ||
const title = paper.paper_title?.ja || paper.paper_title?.en || ''; | ||
const authors = (paper.authors?.ja || paper.authors?.en || []) | ||
.map(author => author.name).join(', '); | ||
const journal = paper.publication_name?.ja || paper.publication_name?.en || ''; | ||
const date = paper.publication_date || ''; | ||
const doi = paper.identifiers?.doi?.[0] || ''; | ||
|
||
return `タイトル:${title}\n` + | ||
`著者:${authors}\n` + | ||
`掲載誌:${journal}\n` + | ||
`出版年:${date}\n` + | ||
(doi ? `DOI:${doi}\n` : '') + | ||
'----------------------------------------\n'; | ||
}).join('\n'); | ||
} | ||
|
||
function escapeCSV(str) { | ||
return str.replace(/"/g, '""'); | ||
} | ||
|
||
// URLパラメータがある場合は自動的に実行 | ||
const urlParams = new URLSearchParams(window.location.search); | ||
const initialUrl = urlParams.get('url'); | ||
if (initialUrl) { | ||
document.getElementById('urlInput').value = initialUrl; | ||
handleSubmit(); | ||
} | ||
</script> | ||
</body> | ||
|
||
</html> |