「Script/track」の編集履歴(バックアップ)一覧はこちら
Script/track - (2019/07/23 (火) 04:10:47) の1つ前との変更点
追加された行は緑色になります。
削除された行は赤色になります。
#divclass(amp_text){{
----
【注意】
現在、このページはJavaScriptの利用が一時制限されています。この表示状態ではトラック情報が正しく表示されません。
この問題は、以下のいずれかが原因となっています。
-ページがAMP表示となっている
-ウィキ内検索からページを表示している
これを解決するには、&this_url(link,base=showpage,text=こちら)を&pc(){クリック}&mobile(){タップ}し、ページを通常表示にしてください。
----
}}
#js(){{
<style type="text/css">
/** General styling **/
@font-face {
font-family: 'Noto Sans JP';
font-display: swap;
font-style: normal;
font-weight: 350;
src: url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/10/NotoSansCJKjp-DemiLight.woff2) format('woff2'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/9/NotoSansCJKjp-DemiLight.woff) format('woff'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/8/NotoSansCJKjp-DemiLight.ttf) format('truetype');
}
@font-face {
font-family: 'Noto Sans JP';
font-display: swap;
font-style: normal;
font-weight: bold;
src: url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/13/NotoSansCJKjp-Medium.woff2) format('woff2'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/12/NotoSansCJKjp-Medium.woff) format('woff'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/11/NotoSansCJKjp-Medium.ttf) format('truetype');
}
rt {
font-family: Arial, Verdana, Helvetica, sans-serif;
}
/** Main table styling **/
#trackinfo, #lyrics {
font-family: 'Noto Sans JP', sans-serif;
font-weight: 350;
}
.track_number {
font-family: Rockwell;
font-weight: bold;
}
.track_number::after {
content: '.';
}
#track_args, .amp_text {
display: none;
}
#trackinfo {
float: right;
margin: 0 0 1em 1em;
padding: 0.3em;
width: 320px;
border-collapse: separate;
border-radius: 5px;
border-spacing: 0;
background-color: #F9F9F9;
font-size: 90%;
line-height: 1.4em;
}
#trackinfo th {
white-space: nowrap;
}
#trackinfo th,
#trackinfo td {
border: none !important;
}
#trackinfo thead th {
background-color: #D8D8D8;
box-shadow: 0 -3px #F9F9F9 inset;
padding: 4px 0 7px 0;
white-space: normal;
font-size: 120%;
text-align: center;
}
.trackrow {
background-color: #F0F0F0;
box-shadow: 0 2px #F9F9F9 inset, 0 -2px #F9F9F9 inset;
}
#trackinfo td ul {
margin: 0;
padding: 0;
list-style: none;
}
#trackinfo li {
line-height: 16px;
}
#trackinfo li:nth-of-type(n+2) {
margin-top: 6px;
}
#trackinfo dl {
margin: 0;
}
#trackinfo dt {
font-size: small;
}
#trackinfo dd {
margin-left: 1.5em;
}
/* Media styling */
#trackinfo .media th {
background-color: #D8D8D8;
padding: 4px 0;
font-size: 95%;
text-align: center;
}
.media td {
padding: 0 2px;
}
.media iframe:nth-of-type(n+2) {
margin-top: 0.3em;
}
.youtube + .nicovideo,
.youtube + .soundcloud,
.nicovideo + .soundcloud {
margin-top: 0.75em;
}
.media_section {
display: flex;
align-items: center;
text-align: center;
}
.media_section::before,
.media_section::after {
display: block;
flex-grow: 1;
content: '';
height: 1px;
}
.media_section::before {
margin-right: 0.5em;
background: linear-gradient(-90deg, #888, transparent);
}
.media_section::after {
margin-left: 0.5em;
background: linear-gradient(90deg, #888, transparent);
}
.media_notice {
color: firebrick;
font-size: 77.5%;
}
/** Lyrics styling **/
#lyrics {
font-size: 1.06em;
line-height: 1.6em;
}
.not_in_card,
.inaudible {
display: inline;
position: relative;
}
.not_in_card {
border-bottom: dashed 1px #D0D0D0;
}
.tooltip {
display: flex;
visibility: hidden;
position: absolute;
top: -42.5px;
left: 0;
width: 275px;
min-height: 20px;
max-height: 100px;
padding: 10px;
border-radius: 5px;
background-color: #555;
align-items: center;
color: #FFF;
font-size: 85%;
line-height: 20px;
text-align: center;
white-space: nowrap;
opacity: 0;
transition: 0.7s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.inaudible .tooltip {
top: -68.5px;
}
span:hover + .tooltip {
visibility: visible;
top: -47.5px;
opacity: 0.8;
transition: 0.3s;
}
.inaudible span:hover + .tooltip {
top: -73.5px;
}
.not_in_card span.hide {
top: -42.5px;
opacity: 0;
transition: 0.7s;
}
.inaudible .img {
display: inline-block;
width: 3.45em;
height: 1.25em;
margin-right: 4px;
margin-bottom: -3.5px;
margin-left: 4px;
background-image: url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2971/7/Inaudible.png);
background-size: contain;
background-repeat: no-repeat;
}
.not_in_card::after,
.inaudible .img::after {
content: ' ';
visibility: hidden;
position: absolute;
top: -8.5px;
left: 42.5%;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
opacity: 0;
transition: 0.7s;
}
.not_in_card:hover::after,
.inaudible .img:hover::after {
content: '';
visibility: visible;
top: -13.5px;
left: 42.5%;
opacity: 0.8;
transition: 0.3s;
}
.not_in_card::after {
top: -2.5px;
left: 50%;
}
.not_in_card:hover::after {
top: -7.5px;
left: 50%;
}
.not_in_card.hide::after {
visibility: hidden;
top: -2.5px;
opacity: 0;
transition: 0.7s;
}
/** For mobile device styling **/
.uk-overflow-container {
display: inline;
}
#trackinfo.mobile {
display: table;
float: none;
width: 100%;
margin: auto;
margin-bottom: 1em;
}
#trackinfo.mobile th {
text-transform: none;
}
#trackinfo.mobile tbody tr:not(.media) th {
text-align: left;
background-color: unset;
}
#trackinfo.mobile td {
white-space: normal;
}
</style>
<script type="text/javascript">
$( function() {
'use strict';
const headers = {
title : 'アルバム別曲名',
album : 'アルバム',
circle : 'サークル',
vocal : 'Vocal',
lyric : 'Lyric',
chorus : 'Chorus',
narrator : 'Narration',
rap : 'Rap',
voice : 'Voice',
whistle : 'Whistle (口笛)',
translate : 'Translation (翻訳)',
arrange : 'Arrange',
artist : 'Artist',
bass : 'Bass',
cajon : 'Cajon (カホン)',
drum : 'Drum',
guitar : 'Guitar',
keyboard : 'Keyboard',
mc : 'MC',
mix : 'Mix',
piano : 'Piano',
sax : 'Sax',
strings : 'Strings',
synthesizer : 'Synthesizer',
trumpet : 'Trumpet',
violin : 'Violin',
original : '原曲',
image_song : 'イメージ曲'
};
const rPagename = /(?=^|.*<)(?!.*")(\w{2})\s(((?!<\/a>).)+)/;
const pagename = $( 'title' ).text().match( /^.+(?=\s-\s東方同人CDの歌詞)/ )[ 0 ];
const $wikibody = $( '#wikibody' );
const $args = $( '#track_args' );
const $lyrics = $( '#lyrics' );
let $pagename, $table;
if ( $wikibody.length ) {
// PC
$pagename = $wikibody.find( '.pagename' );
} else {
// Mobile
$pagename = $( '#atwiki-wrapper' ).find( 'h2.uk-text-middle' );
}
const TrackInfobox = {
init: function() {
// 表生成
$args.after( this.genTable() );
$table = $( '#trackinfo' );
// メディア表示
$table.append( this.fetchMedia() );
// 項目リンク化
this.entryLinking();
// スマホ表示用のスタイル適用
const ua = navigator.userAgent;
if ( ua.match( /(iPhone|iPod|Android)(?=.*Mobile)/ ) ) {
$table.addClass( 'mobile' );
}
// ページ名のトラック番号を太字に
this.modifyPagename();
// 歌詞整形
if ( !this.modifyLyrics() ) {
$table.after(
'<div class="error"><span style="font-weight: bold">Script: track</span>'
+ '<br>曲の歌詞を以下の形式で指定してください。'
+ '<br><br>#divid(lyrics){<br>(ここに歌詞)<br>}'
+ '</div>'
);
} else {
this.modifyLyrics();
}
},
argsObj: function() {
const args = $args.html()
.replace( /\|/, '' )
.replace( /<[!\/]?(!--@+--|div|br)>|\t|\n/g, '' )
.split( '|' );
let hash, data = {};
// 引数をオブジェクト化
for ( let i in args ) {
hash = args[ i ]
.replace( '=', '::' ) // HTML タグ考慮
.split( '::' );
if ( hash[ 1 ].indexOf( ';' ) > -1 ) {
// 複数指定の判定
// HTML タグと文字参照に含まれるセミコロンの対象除外処理
hash[ 1 ] = hash[ 1 ]
.replace( /(<.+?>|&.+?;)/g, function() {
return arguments[ 0 ].replace( ';', ':$:' );
} )
.split( ';' );
$.each( hash[ 1 ], function( i, v ) {
return hash[ 1 ][ i ] = v.replace( /:\$:/g, ';' );
} );
}
data[ hash[ 0 ] ] = hash[ 1 ];
}
return data;
},
genTable: function() {
const tableKeys = Object.keys( this.argsObj() );
const title = this.argsObj()[ 'title' ];
const escValue = /^(\s*|\r|\n|\r\n)$/;
let table = '<table id="trackinfo" border="1"><thead><tr><th colspan="2">';
if ( title ) {
table += ( $.isArray( title ) )
? title[ 0 ]
: title;
} else {
table += ( rPagename.test( pagename ) )
? pagename.slice( 3 )
: ( pagename )
? pagename
: 'トラック情報';
}
table += '</th></tr></thead><tbody>';
for ( let i in tableKeys ) {
const key = tableKeys[ i ];
const value = this.argsObj()[ key ];
if (
escValue.test( value )
|| !headers[ key ]
|| ( key === 'title' && !$.isArray( value ) )
) continue;
table += '<tr class="trackrow ' + key + '">'
+ '<th>' + headers[ key ] + '</th><td>';
if ( $.isArray( value ) ) {
// 複数指定処理
table += '<ul>';
for ( let i in value ) {
if ( key === 'title' && i == 0 ) {
continue;
}
table += '<li>' + value[ i ] + '</li>';
}
table += '</ul>';
} else {
table += value;
}
table += '</td></tr>';
}
table += '</tbody></table>';
return table;
},
fetchMedia: function() {
const media = this.argsObj()[ 'media' ];
if ( !media ) return;
let links = ( $.isArray( media ) )
? media.join()
: media;
links = links.replace( /<.+?>|\s/g, '' );
const ytId = links.match( /(?=^|\b)(?=[\w-]{0,10}[A-Z])(?![sn]m)(?!\s)[\w-]{11}(?=$|,)/g );
const nicoId = links.match( /[sn]m\d{1,14}/g );
let scUrl = links.match( /(?=^|\b)(?!watch|com|jp|be)[\w-]+\/[\w-]+(?=$|,)/ );
let html = '<tr class="trackrow media">'
+ '<th colspan="2">メディア</th>'
+ '</tr><tr class="trackrow media">'
+ '<td colspan="2">';
if ( !ytId && !nicoId && !scUrl ) return;
// YouTube
if ( ytId ) {
html += '<div class="youtube">';
html += nicoId || scUrl
? '<div class="media_section">YouTube</div>'
: '';
for ( let i in ytId ) {
html += '<iframe width="100%" src="'
+ 'https://youtube.com/embed/' + ytId[ i ]
+ '?showinfo=0" frameborder="0" allowfullscreen></iframe>';
}
html += '</div>';
}
// Niconico
if ( nicoId ) {
html += '<div class="nicovideo">';
html += ytId || scUrl
? '<div class="media_section">ニコニコ動画</div>'
: '';
for ( let i in nicoId ) {
html += '<iframe width="100%" src="'
+ 'https://embed.nicovideo.jp/watch/' + nicoId[ i ]
+ '" frameborder="0" allowfullscreen></iframe>';
}
html += '</div>';
}
// Soundcloud
if ( scUrl ) {
html += '<div class="soundcloud">';
html += ytId || nicoId
? '<div class="media_section">Soundcloud</div>'
: '';
html += '</div>';
scUrl = 'https://soundcloud.com/' + scUrl[ 0 ];
scUrl = 'https://soundcloud.com/oembed?format=js&url=' + scUrl + '&callback=?';
$.getJSON( scUrl, function( data ) {
const html = data.html.replace( 'height="400"', '' );
$table.find( '.soundcloud' ).append( html );
} );
}
html += '<span class="media_notice">サークルが公開、もしくはサークルの許可を得て制作されているメディア以外(端的に言えば音楽に画像を貼っただけの無断転載動画)の指定はお控えください</span></td>';
return html;
},
entryLinking: function() {
const target = '.vocal td:not(:has(ul)), .original td:not(:has(ul)), .vocal li, .original li';
return $table.find( target ).html( function( _, elem ) {
const items = elem.match( /[^<>]+(?![^<]*>|[^<>]*<\/)|.*>|.*<\//g );
if ( !items[ 0 ] ) return;
for ( let i in items ) {
items[ i ] = items[ i ].trim();
}
const page = encodeURI( items[ 0 ].replace( /\((.+?)\)/g, '($1)' ) ).trim();
let result;
result = '<a href="/touhoukashi/tag/' + page + '">';
if ( items[ 1 ] ) {
if ( elem.indexOf( items[ 0 ] ) < elem.indexOf( items[ 1 ] ) ) {
// タグがリンクするテキストの後にあったら
result += items[ 0 ] + items[ 1 ];
} else {
// 前にあったら
result += items[ 1 ] + items[ 0 ];
}
} else {
// なかったら
result += items[ 0 ];
}
result += '</a>';
return result;
} );
},
modifyPagename: function() {
return $pagename.html( function() {
return pagename.replace( rPagename, '<span class="track_number">$1</span> $2' );
} );
},
modifyLyrics: function() {
const notInCard = '<div class="not_in_card">'
+ '<span>$1</span>'
+ '<span class="tooltip">この歌詞は歌詞カードへの記載がありません</span>'
+ '</div>';
const inaudible = '<div class="inaudible">'
+ '<span class="img"></span>'
+ '<span class="tooltip">この箇所は歌詞カードへの記載がなく、'
+ '<br>かつ聞き取りが困難であったことを示します</span>'
+ '</div>';
let $notInCard, $tooltip;
if ( !$lyrics.length ) return;
$lyrics.html( function( _, elem ) {
return elem
// 歌詞カード未記載歌詞
.replace( /__(.+?((\n.+?)+?)?)__/g, notInCard )
// 正しく聞き取れなかった歌詞
.replace( /[((]([??]{3}|聴音不可)[))]/g, inaudible );
} );
$table.after( $lyrics );
$notInCard = $lyrics.find( '.not_in_card' );
$tooltip = $notInCard.children( '.tooltip' );
$lyrics.find( '.inaudible' ).on( {
mouseenter: function() {
$tooltip.toggleClass( 'hide' );
$notInCard.toggleClass( 'hide' );
},
mouseleave: function() {
$tooltip.toggleClass( 'hide' );
$notInCard.toggleClass( 'hide' );
}
} );
return true;
}
};
TrackInfobox.init();
} );
</script>
}}
#divclass(amp_text){{
----
【注意】
現在、このページはJavaScriptの利用が一時制限されています。この表示状態ではトラック情報が正しく表示されません。
この問題は、以下のいずれかが原因となっています。
-ページがAMP表示となっている
-ウィキ内検索からページを表示している
これを解決するには、&this_url(link,base=showpage,text=こちら)を&pc(){クリック}&mobile(){タップ}し、ページを通常表示にしてください。
----
}}
#js(){{
<style type="text/css">
/** General styling **/
@font-face {
font-family: 'Noto Sans JP';
font-display: swap;
font-style: normal;
font-weight: 350;
src: url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/10/NotoSansCJKjp-DemiLight.woff2) format('woff2'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/9/NotoSansCJKjp-DemiLight.woff) format('woff'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/8/NotoSansCJKjp-DemiLight.ttf) format('truetype');
}
@font-face {
font-family: 'Noto Sans JP';
font-display: swap;
font-style: normal;
font-weight: bold;
src: url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/13/NotoSansCJKjp-Medium.woff2) format('woff2'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/12/NotoSansCJKjp-Medium.woff) format('woff'),
url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2972/11/NotoSansCJKjp-Medium.ttf) format('truetype');
}
rt {
font-family: Arial, Verdana, Helvetica, sans-serif;
}
/** Main table styling **/
#trackinfo, #lyrics {
font-family: 'Noto Sans JP', sans-serif;
font-weight: 350;
}
.track_number {
font-family: Rockwell;
font-weight: bold;
}
.track_number::after {
content: '.';
}
#track_args, .amp_text {
display: none;
}
#trackinfo {
float: right;
margin: 0 0 1em 1em;
padding: 0.3em;
width: 320px;
border-collapse: separate;
border-radius: 5px;
border-spacing: 0;
background-color: #F9F9F9;
font-size: 90%;
line-height: 1.4em;
}
#trackinfo th {
white-space: nowrap;
}
#trackinfo th,
#trackinfo td {
border: none !important;
}
#trackinfo thead th {
background-color: #D8D8D8;
box-shadow: 0 -3px #F9F9F9 inset;
padding: 4px 0 7px 0;
white-space: normal;
font-size: 120%;
text-align: center;
}
.trackrow {
background-color: #F0F0F0;
box-shadow: 0 2px #F9F9F9 inset, 0 -2px #F9F9F9 inset;
}
#trackinfo td ul {
margin: 0;
padding: 0;
list-style: none;
}
#trackinfo li {
line-height: 16px;
}
#trackinfo li:nth-of-type(n+2) {
margin-top: 6px;
}
#trackinfo dl {
margin: 0;
}
#trackinfo dt {
font-size: small;
}
#trackinfo dd {
margin-left: 1.5em;
}
/* Media styling */
#trackinfo .media th {
background-color: #D8D8D8;
padding: 4px 0;
font-size: 95%;
text-align: center;
}
.media td {
padding: 0 2px;
}
.media iframe:nth-of-type(n+2) {
margin-top: 0.3em;
}
.youtube + .nicovideo,
.youtube + .soundcloud,
.nicovideo + .soundcloud {
margin-top: 0.75em;
}
.media_section {
display: flex;
align-items: center;
text-align: center;
}
.media_section::before,
.media_section::after {
display: block;
flex-grow: 1;
content: '';
height: 1px;
}
.media_section::before {
margin-right: 0.5em;
background: linear-gradient(-90deg, #888, transparent);
}
.media_section::after {
margin-left: 0.5em;
background: linear-gradient(90deg, #888, transparent);
}
.media_notice {
color: firebrick;
font-size: 77.5%;
}
/** Lyrics styling **/
#lyrics {
font-size: 1.06em;
line-height: 1.6em;
}
.not_in_card,
.inaudible {
display: inline;
position: relative;
}
.not_in_card {
border-bottom: dashed 1px #D0D0D0;
}
.tooltip {
display: flex;
visibility: hidden;
position: absolute;
top: -42.5px;
left: 0;
width: 275px;
min-height: 20px;
max-height: 100px;
padding: 10px;
border-radius: 5px;
background-color: #555;
align-items: center;
color: #FFF;
font-size: 85%;
line-height: 20px;
text-align: center;
white-space: nowrap;
opacity: 0;
transition: 0.7s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.inaudible .tooltip {
top: -68.5px;
}
span:hover + .tooltip {
visibility: visible;
top: -47.5px;
opacity: 0.8;
transition: 0.3s;
}
.inaudible span:hover + .tooltip {
top: -73.5px;
}
.not_in_card span.hide {
top: -42.5px;
opacity: 0;
transition: 0.7s;
}
.inaudible .img {
display: inline-block;
width: 3.45em;
height: 1.25em;
margin-right: 4px;
margin-bottom: -3.5px;
margin-left: 4px;
background-image: url(https://img.atwikiimg.com/www31.atwiki.jp/touhoukashi/attach/2971/7/Inaudible.png);
background-size: contain;
background-repeat: no-repeat;
}
.not_in_card::after,
.inaudible .img::after {
content: ' ';
visibility: hidden;
position: absolute;
top: -8.5px;
left: 42.5%;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
opacity: 0;
transition: 0.7s;
}
.not_in_card:hover::after,
.inaudible .img:hover::after {
content: '';
visibility: visible;
top: -13.5px;
left: 42.5%;
opacity: 0.8;
transition: 0.3s;
}
.not_in_card::after {
top: -2.5px;
left: 50%;
}
.not_in_card:hover::after {
top: -7.5px;
left: 50%;
}
.not_in_card.hide::after {
visibility: hidden;
top: -2.5px;
opacity: 0;
transition: 0.7s;
}
/** For mobile device styling **/
.uk-overflow-container {
display: inline;
}
#trackinfo.mobile {
display: table;
float: none;
width: 100%;
margin: auto;
margin-bottom: 1em;
}
#trackinfo.mobile th {
text-transform: none;
}
#trackinfo.mobile tbody tr:not(.media) th {
text-align: left;
background-color: unset;
}
#trackinfo.mobile td {
white-space: normal;
}
</style>
<script type="text/javascript">
$( function() {
'use strict';
const headers = {
title : 'アルバム別曲名',
album : 'アルバム',
circle : 'サークル',
vocal : 'Vocal',
lyric : 'Lyric',
chorus : 'Chorus',
narrator : 'Narration',
rap : 'Rap',
voice : 'Voice',
whistle : 'Whistle (口笛)',
translate : 'Translation (翻訳)',
arrange : 'Arrange',
artist : 'Artist',
bass : 'Bass',
cajon : 'Cajon (カホン)',
drum : 'Drum',
guitar : 'Guitar',
keyboard : 'Keyboard',
mc : 'MC',
mix : 'Mix',
piano : 'Piano',
sax : 'Sax',
strings : 'Strings',
synthesizer : 'Synthesizer',
trumpet : 'Trumpet',
violin : 'Violin',
original : '原曲',
image_song : 'イメージ曲'
};
const rPagename = /(?=^|.*<)(?!.*")(\w{2})\s(((?!<\/a>).)+)/;
const pagename = $( 'title' ).text().match( /^.+(?=\s-\s東方同人CDの歌詞)/ )[ 0 ];
const $wikibody = $( '#wikibody' );
const $args = $( '#track_args' );
const $lyrics = $( '#lyrics' );
let $pagename, $table;
if ( $wikibody.length ) {
// PC
$pagename = $wikibody.find( '.pagename' );
} else {
// Mobile
$pagename = $( '#atwiki-wrapper' ).find( 'h2.uk-text-middle' );
}
const TrackInfobox = {
init: function() {
// 表生成
$args.after( this.genTable() );
$table = $( '#trackinfo' );
// メディア表示
$table.append( this.fetchMedia() );
// 項目リンク化
this.entryLinking();
// スマホ表示用のスタイル適用
const ua = navigator.userAgent;
if ( ua.match( /(iPhone|iPod|Android)(?=.*Mobile)/ ) ) {
$table.addClass( 'mobile' );
}
// ページ名のトラック番号を太字に
this.modifyPagename();
// 歌詞整形
if ( !this.modifyLyrics() ) {
$table.after(
'<div class="error"><span style="font-weight: bold">Script: track</span>'
+ '<br>曲の歌詞を以下の形式で指定してください。'
+ '<br><br>#divid(lyrics){<br>(ここに歌詞)<br>}'
+ '</div>'
);
} else {
this.modifyLyrics();
}
},
argsObj: function() {
const args = $args.html()
.replace( /\|/, '' )
.replace( /<[!\/]?(!--@+--|div|br)>|\t|\n/g, '' )
.split( '|' );
let hash, data = {};
// 引数をオブジェクト化
for ( let i in args ) {
hash = args[ i ]
.replace( '=', '::' ) // HTML タグ考慮
.split( '::' );
if ( hash[ 1 ].indexOf( ';' ) > -1 ) {
// 複数指定の判定
// HTML タグと文字参照に含まれるセミコロンの対象除外処理
hash[ 1 ] = hash[ 1 ]
.replace( /(<.+?>|&.+?;)/g, function() {
return arguments[ 0 ].replace( ';', ':$:' );
} )
.split( ';' );
$.each( hash[ 1 ], function( i, v ) {
return hash[ 1 ][ i ] = v.replace( /:\$:/g, ';' );
} );
}
data[ hash[ 0 ] ] = hash[ 1 ];
}
return data;
},
genTable: function() {
const tableKeys = Object.keys( this.argsObj() );
const title = this.argsObj()[ 'title' ];
const escValue = /^(\s*|\r|\n|\r\n)$/;
let table = '<table id="trackinfo" border="1"><thead><tr><th colspan="2">';
if ( title ) {
table += ( $.isArray( title ) )
? title[ 0 ]
: title;
} else {
table += ( rPagename.test( pagename ) )
? pagename.slice( 3 )
: ( pagename )
? pagename
: 'トラック情報';
}
table += '</th></tr></thead><tbody>';
for ( let i in tableKeys ) {
const key = tableKeys[ i ];
const value = this.argsObj()[ key ];
if (
escValue.test( value )
|| !headers[ key ]
|| ( key === 'title' && !$.isArray( value ) )
) continue;
table += '<tr class="trackrow ' + key + '">'
+ '<th>' + headers[ key ] + '</th><td>';
if ( $.isArray( value ) ) {
// 複数指定処理
table += '<ul>';
for ( let i in value ) {
if ( key === 'title' && i == 0 ) {
continue;
}
table += '<li>' + value[ i ] + '</li>';
}
table += '</ul>';
} else {
table += value;
}
table += '</td></tr>';
}
table += '</tbody></table>';
return table;
},
fetchMedia: function() {
const media = this.argsObj()[ 'media' ];
if ( !media ) return;
let links = ( $.isArray( media ) )
? media.join()
: media;
links = links.replace( /<.+?>|\s/g, '' );
const ytId = links.match( /(?=^|\b)(?=[\w-]{0,10}[A-Z])(?![sn]m)(?!\s)[\w-]{11}(?=$|,)/g );
const nicoId = links.match( /[sn]m\d{1,14}/g );
let scUrl = links.match( /(?=^|\b)(?!watch|com|jp|be)[\w-]+\/[\w-]+(?=$|,)/ );
let html = '<tr class="trackrow media">'
+ '<th colspan="2">メディア</th>'
+ '</tr><tr class="trackrow media">'
+ '<td colspan="2">';
if ( !ytId && !nicoId && !scUrl ) return;
// YouTube
if ( ytId ) {
html += '<div class="youtube">';
html += nicoId || scUrl
? '<div class="media_section">YouTube</div>'
: '';
for ( let i in ytId ) {
html += '<iframe width="100%" src="'
+ 'https://youtube.com/embed/' + ytId[ i ]
+ '?showinfo=0" frameborder="0" allowfullscreen></iframe>';
}
html += '</div>';
}
// Niconico
if ( nicoId ) {
html += '<div class="nicovideo">';
html += ytId || scUrl
? '<div class="media_section">ニコニコ動画</div>'
: '';
for ( let i in nicoId ) {
html += '<iframe width="100%" src="'
+ 'https://embed.nicovideo.jp/watch/' + nicoId[ i ]
+ '" frameborder="0" allowfullscreen></iframe>';
}
html += '</div>';
}
// Soundcloud
if ( scUrl ) {
html += '<div class="soundcloud">';
html += ytId || nicoId
? '<div class="media_section">Soundcloud</div>'
: '';
html += '</div>';
scUrl = 'https://soundcloud.com/' + scUrl[ 0 ];
scUrl = 'https://soundcloud.com/oembed?format=js&url=' + scUrl + '&callback=?';
$.getJSON( scUrl, function( data ) {
const html = data.html.replace( 'height="400"', '' );
$table.find( '.soundcloud' ).append( html );
} );
}
html += '<span class="media_notice">サークルが公開、もしくはサークルの許可を得て制作されているメディア以外(端的に言えば音楽に画像を貼っただけの無断転載動画)の指定はお控えください</span></td>';
return html;
},
entryLinking: function() {
const target = '.vocal td:not(:has(ul)), .original td:not(:has(ul)), .vocal li, .original li';
return $table.find( target ).html( function( _, elem ) {
const items = elem.match( /[^<>]+(?![^<]*>|[^<>]*<\/)|.*>|.*<\//g );
if ( !items[ 0 ] ) return;
for ( let i in items ) {
items[ i ] = items[ i ].trim();
}
const page = encodeURI( items[ 0 ].replace( /\((.+?)\)/g, '($1)' ) ).trim();
let result;
result = '<a href="/touhoukashi/tag/' + page + '">';
if ( items[ 1 ] ) {
if ( elem.indexOf( items[ 0 ] ) < elem.indexOf( items[ 1 ] ) ) {
// タグがリンクするテキストの後にあったら
result += items[ 0 ] + items[ 1 ];
} else {
// 前にあったら
result += items[ 1 ] + items[ 0 ];
}
} else {
// なかったら
result += items[ 0 ];
}
result += '</a>';
return result;
} );
},
modifyPagename: function() {
return $pagename.html( function() {
return pagename.replace( rPagename, '<span class="track_number">$1</span> $2' );
} );
},
modifyLyrics: function() {
const notInCard = '<div class="not_in_card">'
+ '<span>$1</span>'
+ '<span class="tooltip">この歌詞は歌詞カードへの記載がありません</span>'
+ '</div>';
const inaudible = '<div class="inaudible">'
+ '<span class="img"></span>'
+ '<span class="tooltip">この箇所は歌詞カードへの記載がなく、'
+ '<br>かつ聞き取りが困難であったことを示します</span>'
+ '</div>';
let $notInCard, $tooltip;
if ( !$lyrics.length ) return;
$lyrics.html( function( _, elem ) {
return elem
// 歌詞カード未記載歌詞
.replace( /__(.+?((\n.+?)+?)?)__/g, notInCard )
// 正しく聞き取れなかった歌詞
.replace( /[((]([??]{3}|聴音不可)[))]/g, inaudible );
} );
$table.after( $lyrics );
$notInCard = $lyrics.find( '.not_in_card' );
$tooltip = $notInCard.children( '.tooltip' );
$lyrics.find( '.inaudible' ).on( {
mouseenter: function() {
$tooltip.toggleClass( 'hide' );
$notInCard.toggleClass( 'hide' );
},
mouseleave: function() {
$tooltip.toggleClass( 'hide' );
$notInCard.toggleClass( 'hide' );
}
} );
return true;
}
};
TrackInfobox.init();
} );
</script>
}}