Call for Nano

自动发送Nanoなの☆エボリューション应援歌词

// ==UserScript==
// @name         Call for Nano
// @namespace    http://tampermonkey.net/
// @version      0.1.2
// @description  自动发送Nanoなの☆エボリューション应援歌词
// @author       ADDD
// @include      /https?:\/\/live\.bilibili\.com\/?\??.*/
// @include      /https?:\/\/live\.bilibili\.com\/\d+\??.*/
// @include      /https?:\/\/live\.bilibili\.com\/(blanc\/)?\d+\??.*/
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.min.js
// @require      https://cdn.staticfile.org/axios/0.27.2/axios.min.js
// @grant        none
// @license      MIT
// @icon         https://i0.hdslb.com/bfs/garb/d926ea632254c7dff67f7cbf59a0a9eaaf74bb1b.png
// ==/UserScript==

(function() {
    // 歌曲来源 https://shiinanoha.com/archives/10936 - 菜の花字幕组
    const AUDIO_SRC = "https://shiinanoha.com/wp-content/uploads/2022/07/Nano%E3%81%AA%E3%81%AE%E2%98%86%E3%82%A8%E3%83%9C%E3%83%AA%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3.mp3";

    // 打Call图片
    const IMAGE_SRC = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKIAAACiCAMAAAD1LOYpAAAC/VBMVEUAAAAuJjIuJjIbCyEtJTEtJTItJTEwKDQoHywtJjIuJjIbGyUsJTEuJTIvJzMuJjEqIjAqHSpANjcyKTQuJjItJTEtJTEzKzYtJTEtJTEtJjItJTEsJDAoISouJjItJTEtJDAsJDArIy8yKjY3LzstJTE9NkEsJTAsJTEsJDA0KzMtJTEsJTEsJC8qHy4tJTEsIS4yKjYtJTFgWmM5MDUsJDArIzBSRz5KR13/5nL2pq////97gpfdY29UWmwuJjIvJzNJRlz///wwKDX/6HUxKTYxKjc2MD//6XozLDoyKzhIRVr//vf/6oFFQVVDP1M4MkH//fJHQ1n/6X40LTv/6HdCPVE/Okw7NUb9/f1FQldAPE81Lj3//vn/64Q9OEo5NET/7Iv/64c8Nkj6+vr//vT//O3//e//7ZDaYm41LDczKTT//Or/+uD/++RRSF42Ljr29vdXXXBsTWHp6OpnbH84MDx4fpN1e5BhZ3r/98n233Dt7O7Z2Nv/+dn/+NJcYnRBOkU8NEDx8fKCiZx9hJiWkpdyeIz643G3XGp3T2JFPkjk4+bd3eFlX2hJQky1srWfnKH/7pv/7pb/7ZONVGVOR1BPO0dqXUTNy87/8qz/76BudIlqZW1WSV5aU12ol1dRS1RiVkJIPjvT0tb/9cDWYW7GXmzq1GvYw2ZkTGCEdkz/++j/9Lr/87Wrqa+KkKGGgYdrcoaCfYR9eIBwa3LlzmqUVWZ+UWNeSl60olt8bklOQzw/MTz/++fFyNHIxsm7uLyeo7KSl6fonab/8KXTYW7QYG3NYG3JX2zKt2aHUmNFPEJYTEBHNEA6MDbAvsGwtcHfl6F7dn3w2W3BXWurWWmcVWVQUF9VT1hGQ1JYQExcUUDvoaqmo6iNipGLh427gIqkcnyjWGhXVmjRvGTBrl9tTlloSlabi1ORgVC9wMuin6T95XGEXGfGh5GveIJ4c3uTZ3HfymhRUmSMfk9zZUb/++amo6TRjpja1sDVkZrWy5n25IlxPUqOuBDOAAAAOHRSTlMA+PsF/PTo/BPx1Ql/7f3eIQz99ePDsPC6kM+JQg/aoGVdLfv4tP12bk/4mFQ1Gckn6af9+Ek6/rYOZ1IAABdCSURBVHja7FpZTFRXGL6zsg7LDIsssg2LQkvZlNvcmHtnhplxZmDYBpB9m7KvgfgAIgETQ6WK4BLUKG64Q9OouKbRB2vdoolLY9JoE6OJpn1oGtukTz3nXph7QIa5hgHmod/zJOeb//zf9y/nYv/DvhDER6z/IizGfa0Ac0R4B8f4Bfr4y+T9kf4hEZjjYX2Ap4jnJO/fv+vS8O0Dye7OmIMhIclfLu9/efF2z7bS0tL09MuJazDHQrxEPnT51U6zErD7Jhtgu9zXwbIxgR/dWUgolYBfTU1Tc9fkfSexg2WjQNRWSBDK9OymreMjdVUZGd1SXhjmUBCI1VsIZWnLwb2VZRm5uRvz8h7xV2GOBVeqBwSxua6yDPBLS0v7+r2HjxfmUIijdgOKNYBhXtrXEGcbRV9gDoUvPH6DFPdmbAQMIbqlwjjMoeDFOwwpHioDFBmMUiGYQ2G17BigWDvBUrzuIXKwZPQZIojS7N6q3BmKU4+FDlZgAqPbAcWWqty8aYoDv5JRmEMhKvIkofymqS4DUGTwkRJjDoWgyN2AYs0IlDSD+408t9n5Gr4mYiUL99rI7VDSk6xezkjJWc7onRQok/iuWbkmLd7/KZR0F6uXgVHSD0OQlGjIzBKJPINWSugCz10EkZ7dzOiFsR3SE2MRJirGcbwoi8fziVshkr4vC6GkK1m9vG0UIYkoLsFpZGqdeD5Bq7EVgN+gmVBmN+1h9XJWymfDFcoz4gwUxTo+LyRsBYQTEN0JXecgopdU1rwTXEpwCwybVEKe75fYcmNN5BMo6XFULx4WvaziZ+IIirQUX+LujS0v1vn/DvRSu7WKTcYPTq6WLkOjwFEo8nXLH0gv/x+IOXp591jiNp2owmqGGnrbGr44Zlkz0i3xcCHUSx2bjH+d4DFxWi3hG/BPYNR68PyW08kFrmNmWALvsBS7H/HdmTwVavF5oCinhIHLedmrhsxQLxO0XhjccIpiJhthMT4vMtV8z7XYsiE0egssgb1IfTka6ypgxTIfjHq+OM4NWya4R96CemlG9HJf6gNzLYifhVuDUceX+K7//LRyXh/uHhCaFLXKNTEwNIaj7MIjhwmol0q2vkzddAmGWeqRjy/A0UPi+RkWKfAKD/L7ylMskbiIRDK5XGfS+vtIwrgtTYDrzBmxuo/LgjDsSxeNAbeOIpOHSBIqwLwj4GLSPSZsbYS3wIprrAsNFLu4yGRybUV1QX6RQaFQ0LpLTOI2YQHXgck4Wcbq5XysH8gAnhZfCDlZGj7vK1exiMcXUpSQz+eLxK5RMXPa39Xr4lxFfL6TrqLASBNDkRXCzRhDXpphMs7SS0qgm7cvr3xBisYKDaVy4vHVao1er9eo1RRFkSQp5Pn4TS97BcFxITyh0ENXkTm/7ioknPxV4Du4DSZjc1XGRlQv6z2dinDryNRq1KaK/GJwb5bjDZkFm0o0kKfINzw+ODREJCRVpgLr6VIt4mavSdHfEcC85+pljVinsB5BrUaTZSU0ipxqnQreOwiwttiAL4Byp7UcJ6wnBEzGkVl6cQ9ysWo5igKdviIHXwCKYhO4dk2xAl8QBaJwjq6znYDJCFpGtr7ERoWKyq1esgkQtIWiCjWly7f6F6rLC4ozy124rRUi/J/SFLvKZtWXVbwiqzEy4hwAmyJ1hcFKddLrdA1tbZSPX0ywbXN1TtxlhsnYDCiyehEHyg34YlGk1WiL5vOr6rEDt4cv7RpUaZycRJ4BtsqUt+v+dtq8EUmfudkgL1Hgi4aiuERrnEcmpssEQGHP8PDFl/1yuX9Sgg3XAeMLnFSREav7VxVVgdsDhk3azE+Im/TbCZqj2UyYd766PCSXxC/c60SepJPxTgaiF4oswO2D/E/CaFTpb4F7g08p6aWlSmVhZzQ/wUav8z0Bk7ELKYFHKdKILxXKVdHbwCtA9oXa2trsb9JLlYVtIsHCex3ZRZriVlQvjWQOvlQoUY/B5O+qqxuZ6G0BJLeoxQIbE9Zh+vXlAqqXxqWLYo5GDXdd2XfASwpA5cj4v5SrDdfxfElLuraOTcaBE1Q+vkQophp64LhUB15SaORdJ+Ns9DqBfVvoN6xDqF5U1fgSIYvsg6th2LekMfjoYeslxS+yh5b0OFICjzZq8SWChjo8PS1Znin4XrZXtYxeEEm/fWxSTLuvnZOyiFLDzTC6dk2V2Vq5hcl+gBTTW5CudkqqoSVtKFFtsrPlkP3fEcBxRlhxnvCx3Ugwkq5FpsDuVLURMjRRWQr7UtRSY2awRWphnwC6pYE2t8mJY+0E9NIRRC+jaihpLQnu275QUa9BOJq2svE4mxKF2Wwk+jppvUwiFM83VsNLURvszNBAgeqnzP6xi6V4PTaIw+tLD62XXkTS1xuzcCNF2tUdFeX5wBWjO+EqbqIyY+asDzLb80EAI+l0tGV826hX6Mgs3K4o0eRoKdCelta2HKq02McN/3ibFMNiGUnXoJJuUFXb/ZozVWCyBeFIr2neg9iip8D2bCBKZr6R2MsawTMpRV+zvcNINZyk1bK3zHJUqi9mE86SwXZmxEKq9E2SnCkwrfYLo5rsgwW6qavOQnFA6sdhI+HZ1sm0jIikj5MkM3ccubvh1D57CUZHHesEgr4wzgp6KiWAyx5Uc6twbgn8SKpwGg82ANQ/sE8oTUAtgGLLHVYt71K4jKoBTq/pfqwJHVRnKF7dQKPeLpHUq38joKBHqiz39d5/HZdx3yO5c7pltFA8S5EG5qLvbWBwasfiL1q1+TYtaEQt5/29OH2ZNUj3Y2jLONVoEfSbDdO417Fo1xncCSn2IrEYTeSykvYWbX4C9ZI9wVJ89pi0dLXXvp0h+e21RVGsVo21w4RCyt/AI1dO+2SxfpgpgYjrpJJIV9txeppj/ZVFtTnqPwn6zZFVy8AJbt+AfaV6StAjFqKX46QOR3DuzSmG5M/XFuE5bb8TsIk4xNaWM9JQbhs8j2QCALSMLMUbpGpOI/agniF55bMbtGsdO47A4U8dfQAKunkvK+j7Ke7cvsziD5lpvezJ3ciO+9TcnVHrOSYpn3+GSbbu+LZ+xg/y9fu/g2rZWscK+n0styVjAq9/C52Mk7mWv/eWouZZmuygOZ5u5UbvKpPCTIK04pv0ye1M+UM9J4ETRWcXfQ+djF0sxWcN1Hxjy5Gf4HkcfHzHPRA9BHdbFdq2izAV/5lkBf3HaCLHzxl8KHqxU/oPTZGBlGIljaiGPvjFwtF78Jyhh+IqbtBFvwKH1ILyl5Fm8ZwQN46vldQlgnbG3DwLxZuUbu7R++5azrOKcy9Yeiyed+CA4iCjlj2s53RLuX5hHEON0RSVGWlsr9OoUaA3fOVny4G/WGfYMZdc/b0X+zpA7iJqQQQ9lZKEcUOwcJCgOR6yMPzj/GN1ERvAF0hWncOt4zn7u1OnAbkjSG1pSG4HFJt6EbW8Swni/LHlZoLGBB39s0fPjz7aL1UVzyjzHqLMhQs1Y0s/Pb/CRA6Ftu0SbdzjdWV5Fs+RhXOk6CbWg/pu3rZz94e/j6eeePjw4bE/d18mmW3yPuTaTtvqJM5N2/s886lu8ytIseUgslO4IYvg+BYLutqxsf1DQ0N9/X3Hdj3dfruTaN/5mjKxVghR/4a9YlvJWD+7dUNqS8sIUqGPJzpzi+F/xZx3bBtVHMc5x0kIkBTEakLKVFkFipinJOT3Tk931p0l+3Sy7POQYpGAFAckE2ongSKSNIOKlk3DCKCyJUbLEjNitGIICFBWadkUyt5CIIZ457N97+x3lxAb9fdHpEhx/PXv3uf9xvs977PbAWjkyocefmBi4sPX155H/Llmw2QmA6L16OwO1IKRLuN0RxOEcj/msb+zxOFBad0KE+gzLaCf2mO+h9pHeSFLaoMosZ5Va54eH+rv7ByeREgoVAZ3vnsz3Tviaj1eACxiJMo+Pa7ZhT6a/1DP2zzZRWKLGf4soO+e955zvAeATMr3vDE2NjY+3tEx3Emsf0CEQG4tvvS2/akF6vdoPmk5B+lsqq8PGSbKSfpI8ubVxdzNgkZVCC0l4e/zUw6Z57WcRtAReqY9+nSHaUOdhg2GoItdJMFeu9UsRjMftG354dPvd26fSWEAQHKc2uVfKoh8Ny9SCKU3GLTcS3ol1FHeXvOMLSAKElxJzpPGTYkP5iRORsDH7mLC8j2P8vb90FawzZ9sBy8AKF2CFaN7CyJfNoGWRgktdPVH7B6rn+Nqp3ohyPuAnHqtGDMlDuYkPvgrKKvvMiAt7WLO7Lusrv7TNso2Z/c7ZikH4KMcWSwnnjf+QUy83KDl7HOvIrQUkwirtnK/sAEJno/Auvb28zZ1mJaTmMmgvjNW8/y7vXaNPvT91BH7/txms537Hrrb0RxgW7LzgpVDkPB3ck+u+qNoufDV/XafF82AYgQBIDPePc/lJfYbEocGUN+d5J16ny9pqONPfviSKLTZJ8e2HNSAANnZfiwvspeEP5MWOvyRzlHLfPKcJQ25Hp2G0ivbo2+YCk2khwckRNbRZ6V5De7b3FZmm6fqufrZ8oO5a3vzEn0ps26heiWkQXvAvOadAGkGcAittZDOmLuOD0XKnciL2TaG/Tg78/0fIsTLksd3ichHCdDZ242N2wp/dIPWPbI05COxgkgtXUB6utOwgTBx8LWlKbaQmm1j2ZYtbW0z0M0qX8ha1qSRNbmleCMN9LGHzmdUFZCWh4C0W9bkJQ6Yu86vIPMv9vKlEqfanGwKdKepFHF9LhOzwh+x6+aVRDQWusU6kEJ11RiN9PQQiPydq/+DxC8h6XQurdwUzdFyjQ3oE2wh5JhlpzLKUygs8DBaF23v2UgjnZnESCjLvgTFWeJOxJR4vgH0AzlaLrA6TiRC00lEzWF7NB7YWL6VLyr2HALoSIL0c3QIHBoUkVbeUxBnPnD0IrNqfIdsrKqyIVda3U933+gTl9blnEfvgsbW0mzbW0RQwylSqH5jRzrE6nfLqT+cJG5nRfXHe18krhdzQJ9LVX8E6OaikP293lCAF3ze5SWpzyFWV0SQRYL07XmJkybSOust9dTPThJnEWO49a4zHue1vvQa+qjADnTNQbWAc/HdL3N2N+5TByoV1z4iUbqDRnpwG+voJZja7vCkt6SQn1EqrCae7DPG5846h6r+SI3JmUC37gfgy78w6FlqzxO9EKSafzeRKG1DenIrhBgNLl/6R7bET7GP4cTem0mcR+t6DFroZPHC23LTgXue5AUlaHXP6mxhey+6+xXG68nczCY6BE73g8Sz3Di1hb0UcZAvs+eJE1/8By7L0XIfRcvdqUUkQp9WB0gX6JFBejuvaaGTp5h46YoSpDMZjJnDkakvN7Oc2Bdide5IfOmdhY9zmdgNFi3ffdG3eLeaZg6UmO3zexbXUBI5GlhBGl1jIE1ltcOTEhZY56GJ9M5yjZ+kRKcRgJsxbMjRQlV/F37d1Lx7i+lCyvwKnaAdb8+dEunrS5DuH1DZ76olUlOf2pnZsrMPOw4U+gGRPYccrF1NlVa3Nu3VCDhYttJrT6O3HMW2maSvIFG6g+ZlQJXi7PdMinjmyx///CBfGHy/PY2Q81RKGFLGxZp7SbJIXf4BjnUkr3NU+rOfPS8JZ0lTfmUHHQIHQyjidECRELGYnpmdmpqdeiUrilIy5nJUAKOrjLrlDoqWLxCIEdY/rqcWIwcB+yog1PXYJO6QcJh3nrWM6KqaVEkhHQ5q7kcFsL6nNFn8CoD5Iq3+4OJi3L0kjY9BlrSTxy2kf+2SkBrjq2AyXBYtTRZ/QyGHc4WGw60sB9s9DIg86Y254DKY2ZpMKKKia0IVFAoY3iRLkaKF2PtId3B5bTHdaYZESesKZT9+ZnDrtohK1CFQ1HBF+oKqIkqyqsf9MYR+N6p8urQic2lsEgkvxfp/aWmOEJRFPDoqyyE5oeoKJCtynC5BwZAE+HqaFvMEDznsohErTC+CGB9XELbmXf0BMu6umfcUQuCrZO6KqMKyHun2KRghjNKrCC10bCHfC4D8Dt73FBOyBtDMT4pZHk9AogIfJsEnWB/cJ46YpdWZ9KSp6PTxmhYV6gUPlsBzwKnNXlD9VZbIS1ijgUbrymh5EiUchzDrTixKRC1LzCJQYHBVyYMOIPrFgiReZmRiF1N1CwGaJsGObcPxhQfdcEiN2dQxuBGEEomV4KLaaI2J2YeihJYLTFpMu815xibEFWYu91+cf+QHAeZjqupT9aBASexa+FJUbFNIcTyy/pabHvj9r78JLQV7DWmOH5A7ulBzFeLMiV7wITAMKXGhWCdEFs4zlm3pJXrkip/WX3rpK6+cfutvXz/xy1uXkBuRfdhx001yzYVeCdW+M0ySEAAqXAsIofjC583tBULImMKKrnh24s3L1o+MvnLpU7c99f77fc40dnPLysdpgduLUwReiyRwfgsSFBRc+N0C0RbbRHx7e3Ttc9+sXbnyome/nZh44OGHrrwNOa+jCFfeMGs9+LhjPFI+wgAKmuPX2oIlRqQI/SsSV+aabuNjYxs3jW/ctGnj2KYUOHsgzvjOnD1ba47zKvldSQbjel1AIj8XarpEx7YApKPF1mWm07D+QYT8zsGd2591fHWcVy78AYJu8lOUFy5RtQHdBSPtxdJyOCdxKIOQ4CzR01LDGmIE2UqRsUAk+hae5vgUgf4NTrYK9H6z078DJJeNn2vZhyXRKur9IkT4eCXT0iGZlqjABCk4xqmziM7JbW6xK+g5eAlrbowKyRHi0SQOVzCPY6uaMCKV5UV0+7dzIMm4UEOfju3OOnwBHxUcUEyugBZB8dmAxue1R/P1+VBeogwBF4lW9WJv7ySoBY50XEESIUg+W72RjRa7HP15oDFoLsGpnmRj5Xa4VxboJ4XjFUgUVXojhsuL7d+BThPoaUCCixcx04t7e2kKI0olN9j8Nokq3GQ00emlmBlCilsq18T04hJOFOhmQ4CvQKKUtOWzE8WjiIwpcXqrazIaY+NSU0tnHkJFE92aSEsUMbmw9jS9cXcORkB386JnD+YIVF2TbQFXJlGlgVZWFMNffx5oFcK8G9HscQTrbn7F5scqpRdlVxGgaVr6J2UUcHvQ3HLm6eVST1e1JAoSJTFM7loVgB7MS3wQY83NixypUhm2zKv+LxK74L1oAegHTYnDQ0gWXCUuZp+oehLVk+ijKy0yLrB2nI4tGXeg+TC3lD3czSlVk6hQMTqEPioFenqb1S1lZ92HsAdhGrBWLYky9RwlvKEIdKdpg6PIFc0urpk9CVPXFKyWxAQVqbByPQHaRstkFrt2LZOcw2jMwd541a6piQI1s7+CAG2jZVqWXMOr6vQ9A/t79GpJVHHAupdPhp1X2WgZyojuZCZqW9kSmz1Vu1HXjSIFhbJ4OQHaRktmWHJ1hhAinWSmncpJ1eIljJJ5NjHCI9EC0P15oHcorrT45TqHAaMljVULgf58Yy6OkIrTG3pKgI643zvT6hc5DRjt4dWrtnfneIlh6I6pKP3QmB1oCVyBjtWT+Me2Q7y+ai3GBNKMNQUhQdB0JRXq3rYjM1gAegdA0D24kH6J42IMVEmibvASzs/XCGE1IUlKKBRSkxH/1m0SyH73nXuZ88xvU6RKEoNGl1a2mqiCFtfVhCxLoiIiLLvHiKTL16/s700KVVqMWOS10raNIHTpwVg4EvDPEZtqT3O++ekJVWvbCaFAFyTKLzZ1z2M7UOr2drmwgYNV27x1X/mIWwRbql32HJJzO9pib0SoVm0gy+XtuYAkzg1kuN4CmpUzVm3b8WFFYgwsoLmB1LmjXG+nevzVYlpUfIxL3FJw7kzO/VupmqtXY6khhpqAqs1NCxnHc7G9GyShWnHaz2Rhbvd75hiYP8kT53etdTul3NaXqIb4XWpCouG0uS4ic0F+V1qMI01kd1tysMrvGqNzCHdrXbQrVyMpCqy65V/o+lXh+RDxAwAAAABJRU5ErkJggg==";

    // Nano用户Id
    const NANO_UID = 623441612;

    // Nano直播间Id
    const NANO_ROOM_ID = 22347054;

    // 弹幕间隔时间
    const INTERVAL = 1000;

    // 原曲歌词
    const ORIGIN_LYRICS = [
        { time:"00:00.00", content:""},
        { time:"00:02.32", content:"Nanoなの☆はい!"},
        { time:"00:14.54", content:"ぐるぐる迷路 地図片手に"},
        { time:"00:20.67", content:"指差し確認して 準備OK"},
        { time:"00:26.25", content:"朝まで解いた宿題持って"},
        { time:"00:30.76", content:"今日もいってきます(いってきまーす)"},
        { time:"00:36.69", content:"天気予報土砂降り雨でも"},
        { time:"00:42.31", content:"傘なんていらない!いっせーのでJump!"},
        { time:"00:47.52", content:"背伸びしても届かないなら"},
        { time:"00:53.47", content:"お空目指して 羽ばたこう"},
        { time:"00:59.02", content:"謎々だらけ この地球を"},
        { time:"01:04.61", content:"ぐるっと一回り"},
        { time:"01:10.15", content:"小っちゃくても大きいハートで"},
        { time:"01:12.70", content:"あなたの一番になりたいから"},
        { time:"01:15.57", content:"私のプログレス ずっと見ていて"},
        { time:"01:18.96", content:"やっぱり君なの Nanoなの☆yeah!"},
        { time:"01:32.64", content:"大きめブラシふんわりチーク"},
        { time:"01:38.83", content:"赤いマニキュア フリルのスカート"},
        { time:"01:44.36", content:"鏡の私とウインク練習"},
        { time:"01:48.92", content:"上手にできるかな?"},
        { time:"01:54.84", content:"あれもこれも 過ぎてく時間に"},
        { time:"02:00.47", content:"待って待って追いかけてjump!"},
        { time:"02:05.64", content:"あなたの瞳に小さくても"},
        { time:"02:11.59", content:"私可愛く映っていますか?"},
        { time:"02:17.16", content:"昨日の涙拭ったら"},
        { time:"02:22.75", content:"明日を迎えに行くの"},
        { time:"02:28.32", content:"小っちゃくても大きいハートで"},
        { time:"02:30.92", content:"あなたの一番でいられるなら"},
        { time:"02:33.75", content:"楽しいことは10億倍 やっぱり君なの"},
        { time:"03:01.46", content:"こんなに小さな声でも"},
        { time:"03:07.43", content:"見つけてくれてありがとう"},
        { time:"03:12.94", content:"これからもずっとずっと"},
        { time:"03:18.54", content:"そばにいてくれますか?"},
        { time:"03:26.54", content:"背伸びしても届かないなら"},
        { time:"03:32.52", content:"お空目指して 羽ばたこう"},
        { time:"03:38.11", content:"謎々だらけ この地球を"},
        { time:"03:43.71", content:"ぐるっと一回り"},
        { time:"03:49.27", content:"小っちゃくても大きいハートで"},
        { time:"03:51.94", content:"あなたの一番になりたいから"},
        { time:"03:54.66", content:"私のプログレス ずっと見ていて"},
        { time:"03:58.04", content:"やっぱり君なの Nanoなの☆yeah!"},
        { time:"04:12.14", content:"Nanoなの☆"},
    ];

    // 打call歌词
    const CHEER_LYRICS = [
        { mode: [], time: "00:00.00", content: "" },
        { mode: [1], time: "00:03.18", content: "嗨!" },
        { mode: [2], time: "00:03.58", content: "wu oi!wu oi!wu oi!wu oi!" }, // ウーオイ!ウーオイ!ウーオイ!ウーオイ!  // 过长
        { mode: [3], time: "00:06.36", content: "a~👏👏sha-ikuzo!" }, // あーーよっしゃいくぞー!
        { mode: [1, 2], time: "00:09.49", content: "tiger fire cyber fiber" }, // タイガー!ファイヤー!サイバー!ファイバー! // 过长
        { mode: [3], time: "00:12.25", content: "diver viber jia-jia-!" }, // ダイバー!バイバー!ジャージャー! // 过长
        { mode: [1, 2], time: "00:19.27", content: "nanoha-!" },
        { mode: [3], time: "00:23.13", content: "cho-zetu kawaii nanoha-!" }, // 问就是 「超絶可愛い なのはー!」 有b站屏蔽词 // 过长
        { mode: [1, 3], time: "00:30.41", content: "nanoha-!" },
        { mode: [2], time: "00:34.26", content: "cho-zetu kawaii nanoha-!" }, // 问就是 「超絶可愛い なのはー!」 有b站屏蔽词 // 过长
        { mode: [1, 3], time: "00:37.05", content: "na-noha! na-noha!" },
        { mode: [2], time: "00:39.85", content: "na-noha! na-noha!" }, // 频率过快
        { mode: [2, 3], time: "00:45.76", content: "yeah tiger faibo wiper" }, // タイガー!ファイボー!ワイパー! // 过长
        { mode: [1], time: "00:49.48", content: "Ah-fufu-!" },
        { mode: [2], time: "00:52.43", content: "👏👏 fuwafuwa!" },
        { mode: [1], time: "00:55.58", content: "嗨 se-no!" },
        { mode: [3], time: "00:56.57", content: "嗨~嗨!嗨嗨嗨嗨" },
        { mode: [2], time: "01:00.64", content: "Ah-fufu-!" },
        { mode: [1, 3], time: "01:03.46", content: "👏👏 fuwafuwa!" },
        { mode: [1, 2, 3], time: "01:10.56", content: "喔~嗨!喔~嗨!喔~嗨!喔~嗨!" },
        { mode: [1], time: "01:21.33", content: "嗨!" },
        { mode: [2], time: "01:21.75", content: "wu oi!wu oi!wu oi!wu oi!" }, // ウーオイ!ウーオイ!ウーオイ!ウーオイ! // 过长
        { mode: [3], time: "01:24.49", content: "a~👏👏sha-ikuzo!" },
        { mode: [2, 3], time: "01:27.64", content: "tora hi jinzou seni" }, // 问就是 「(se)ni 」是b站屏蔽词 // 虎(とら)、火(ひ)、人造(じんぞう)、繊维(せんい)
        { mode: [1], time: "01:30.42", content: "ama shindou kasse-n!" }, // 海女(あま)、振动(しんどう)、化繊飞除去(かせんとびじょきょ)
        { mode: [2, 3], time: "01:37.39", content: "nanoha-!" }, // なのはー!
        { mode: [1], time: "01:41.25", content: "cho-zetu kawaii nanoha-!" }, // 问就是 「超絶可愛い なのはー!」 有b站屏蔽词 // 过长
        { mode: [1, 3], time: "01:48.58", content: "nanoha-!" }, // なのはー!
        { mode: [2], time: "01:52.41", content: "cho-zetu kawaii nanoha-!" }, // 问就是 「超絶可愛い なのはー!」 有b站屏蔽词 // 过长
        { mode: [1, 2], time: "02:03.92", content: "yeah tiger faibo wiper" }, // 过长
        { mode: [3], time: "02:07.61", content: "Ah-fufu-!" },
        { mode: [1, 2], time: "02:10.56", content: "👏👏 fuwafuwa!" },
        { mode: [3], time: "02:13.71", content: "嗨 se-no!" },
        { mode: [1, 2], time: "02:14.75", content: "嗨~嗨!嗨嗨嗨嗨" },
        { mode: [3], time: "02:18.76", content: "Ah-fufu-!" },
        { mode: [1, 2], time: "02:21.74", content: "👏👏 fuwafuwa!" },
        { mode: [1, 2, 3], time: "02:28.71", content: "喔~嗨!喔~嗨!喔~嗨!喔~嗨!" },
        { mode: [2, 3], time: "02:39.87", content: "iitai kotoga arundayo" }, // 言いたいことがあるんだよ! // 过长
        { mode: [1], time: "02:42.60", content: "yappari nanohawa kawaiiyo" }, // やっぱりなのははかわいいよ! // 过长
        { mode: [3], time: "02:45.46", content: "suki suki daisuki yappa suki" }, // すきすき大好き!やっぱ好き! // 过长
        { mode: [1], time: "02:48.22", content: "yatto mituketa ohimesama" }, // 问就是 「やっと見つけたお姫様!」 有b站屏蔽词 // 过长
        { mode: [2], time: "02:50.96", content: "orega umarete kitariyuu" }, // 俺が生まれてきた理由! // 过长
        { mode: [3], time: "02:53.80", content: "sorewa nanohani deautame" }, // 问就是 「それはなのはに出会うため!」 有b站屏蔽词 // 过长
        { mode: [1, 2], time: "02:56.56", content: "oreto Isshoni jinsei ayumou" }, // 问就是 jin(se)i 是b站屏蔽词 俺と一緒に人生歩もう // 过长
        { mode: [3], time: "02:59.32", content: "sekaide itiban aishiteru-!" }, // 世界で一番愛してる! // 过长
        { mode: [2, 3], time: "03:24.53", content: "👏👏👏👏" },
        { mode: [1], time: "03:27.31", content: "👏~👏~👏~👏~" },
        { mode: [3], time: "03:34.57", content: "嗨 se-no!" },
        { mode: [1], time: "03:35.63", content: "嗨~嗨!嗨嗨嗨嗨" },
        { mode: [2], time: "03:39.69", content: "Ah-fufu-!" },
        { mode: [1, 3], time: "03:42.72", content: "👏👏 fuwafuwa!" },
        { mode: [1, 3], time: "03:49.64", content: "喔~嗨!喔~嗨!喔~嗨!喔~嗨!" },
        { mode: [2], time: "03:50.64", content: "👏👏👏👏*4" },
        { mode: [3], time: "04:00.42", content: "嗨!" },
        { mode: [1], time: "04:00.80", content: "wu oi!wu oi!wu oi!wu oi!" }, // ウーオイ!ウーオイ!ウーオイ!ウーオイ! // 过长
        { mode: [2], time: "04:03.60", content: "wu oi!wu oi!wu oi!wu oi!" }, // ウーオイ!ウーオイ!ウーオイ!ウーオイ! // 过长
        { mode: [1, 3], time: "04:06.36", content: "wu oi!wu oi!wu oi!wu oi!" }, // ウーオイ!ウーオイ!ウーオイ!ウーオイ! // 过长
        { mode: [1, 2, 3], time: "04:13.42", content: "foo-!" },
    ];

    // 布局设置
    const setup = () => {
        $(".player-section").append(
            `<style>
      #call-container {
        position: absolute;
        left: 10%;
        top: 10%;
        color: white;
        font-size: 1.2rem;
        font-family: "微软雅黑";
      }

      #call-img-container {
        position: absolute;
      }

      #action-container {
        position: absolute;
        width: 440px;
        background-color: #333;
        margin: auto;
        opacity: 0.9;
      }

      #lyric-content {
        width: 440px;
        height: 480px;
        overflow: hidden;
        position: relative;
        opacity: 0.9;
      }

      #action-bar {
        display: flex;
        flex-direction: row;
        margin: 14px;
        align-items: center;
      }

      #button-group {
        display: flex;
        height: 54px;
        flex-direction: column;
        align-items: flex-start;
        justify-content: space-around;
      }

      #button-group button {
        display: flex;
        color: black;
        font-size: 0.8rem;
      }

      #audio-container {
        display: flex;
      }

      #audio-container audio {
        display: flex;
        height: 30px;
      }

      #call-img {
        width: 50px;
        height: 50px;
        border-radius: 10px;
      }

      #lyric-content ul {
        width: 100%;
        position: absolute;
        top: 0;
        left: 0;
        list-style: none;
      }

      .original {
        height: 30px;
        line-height: 30px;
        text-align: left;
        padding-left: 30px;
      }

      .original.active {
        color: #2ecc71;
        font-weight: bold;
        font-size: 20px;
      }

      .cheerful {
        height: 30px;
        line-height: 30px;
        text-align: right;
        padding-right: 30px;
      }

      .cheerful.active {
        color: #f35858;
        font-weight: bold;
        font-size: 20px;
      }
      </style>

      <div id="call-container">
        <div id="call-img-container">
          <img id="call-img" />
        </div>
        <div id="action-container">
          <div id="lyric-content"></div>
          <div id="action-bar">
            <div id="button-group">
              <button id="mode">模式1</button>
              <button id="call">点我打Call</button>
            </div>
            <div id="audio-container">
              <audio controls></audio>
            </div>
          </div>
        </div>
      </div>`);
    };

    // 初始化插件
    const initCheer = () => {
        const $ul = $("<ul></ul>");
        const parsedOriginLyrics = [];
        const parsedCheerLyrics = [];
        let isCalling = false;
        let mode = 0;
        const audio = $("#audio-container audio")[0];

        // 初始化音频
        const initAudio = (audioSrc) => {
            audio.src = audioSrc;
            audio.muted = true;

            let lastCheerLineNo = 0;
            let timer = null;
            // 当快进或者倒退时 找到该时点所属行
            const getLineNo = (currentTime, lyrics) => {
                const length = lyrics.length - 1;
                for (let i = 0; i < length; ++i) {
                    if (
                        currentTime >= parseFloat(lyrics[i].time) &&
                        currentTime < parseFloat(lyrics[i + 1].time)
                    ) {
                        return i;
                    }
                }
                return length;
            };
            // 节流
            const throttle = (func) => {
                timer = setTimeout(() => {
                    func;
                    timer = null;
                }, INTERVAL);
            };

            // 歌曲播放时渲染
            audio.addEventListener("timeupdate", () => {
                const MIN_SCROLL_LINE = 6; // 第6行起开始滚动歌词
                const LINE_HEIGHT = -30; // 每次滚动的距离

                if ($("li").eq(0).hasClass("active")) {
                    $("ul").css("top", "0");
                }
                // 获取原曲该时点播放行
                const originLineNo = getLineNo(audio.currentTime, parsedOriginLyrics);
                // 获取打call时该时点播放行
                const cheerLineNo = getLineNo(audio.currentTime, parsedCheerLyrics);
                // 输出模式判断
                // if (isCalling && timer === null && cheerLineNo !== lastCheerLineNo && parsedCheerLyrics[cheerLineNo].mode.includes(mode + 1)) {
                if (isCalling && timer === null && cheerLineNo !== lastCheerLineNo) {
                    // 播放其他行歌词
                    lastCheerLineNo = cheerLineNo;
                    // 发送弹幕
                    throttle(sendMessage(parsedCheerLyrics[cheerLineNo].content));
                }
                // 歌词高亮
                $("li.original")
                    .eq(originLineNo)
                    .addClass("active")
                    .siblings(".original")
                    .removeClass("active");
                $("li.cheerful")
                    .eq(cheerLineNo)
                    .addClass("active")
                    .siblings(".cheerful")
                    .removeClass("active");
                // 滚动播放
                if (originLineNo > MIN_SCROLL_LINE || cheerLineNo > MIN_SCROLL_LINE) {
                    $ul
                        .stop(true, true)
                        .animate({ top: (originLineNo + cheerLineNo - MIN_SCROLL_LINE) * LINE_HEIGHT });
                }
            });
        };

        // 初始化歌词内容
        const initLyricContent = (originalLyrics, cheerLyrics) => {
            const lyricContent = $("#lyric-content");

            // 时间处理
            const parseTimeFromLyric = (lyric) => {
                const splittedTime = lyric.time.split(":");
                const minute = splittedTime[0];
                const second = splittedTime[1];
                return (parseInt(minute) * 60 + parseFloat(second)).toFixed(4) - 0;
            };

            // 文本处理
            const parseContentFromLyric = (lyric) => {
                return lyric.content;
            };

            originalLyrics.forEach((lyric) => {
                parsedOriginLyrics.push({
                    time: parseTimeFromLyric(lyric),
                    content: parseContentFromLyric(lyric),
                });
            });

            cheerLyrics.forEach((lyric) => {
                parsedCheerLyrics.push({
                    mode: lyric.mode,
                    time: parseTimeFromLyric(lyric),
                    content: parseContentFromLyric(lyric),
                });
            });

            const originLength = parsedOriginLyrics.length;
            const cheerLength = parsedCheerLyrics.length;
            let i = 0, j = 0;
            while (i < originLength && j < cheerLength) {
                const $li = $("<li></li>");
                // 根据时间设置歌词
                if (parsedOriginLyrics[i].time <= parsedCheerLyrics[j].time) {
                    // 设置原曲歌词
                    $li.text(parsedOriginLyrics[i++].content).addClass("original");
                } else {
                    // 设置打call歌词
                    $li.text(parsedCheerLyrics[j++].content).addClass("cheerful");
                }
                $ul.append($li);
            }
            // 追加结尾处歌词
            while (i < originLength) {
                const $li = $("<li></li>");
                $li.text(parsedOriginLyrics[i++].content).addClass("original");
                $ul.append($li);
            }
            while (j < cheerLength) {
                const $li = $("<li></li>");
                $li.text(parsedCheerLyrics[j++].content).addClass("cheerful");
                $ul.append($li);
            }

            lyricContent.append($ul);
        };

        // 初始化操作入口
        const initEntrance = () => {
            const actor = $("#action-container");
            const callImg = $("#call-img");
            const modeButton = $("#mode");
            const callButton = $("#call");

            const imageSrc = IMAGE_SRC;
            callImg.attr("src", imageSrc);
            callImg.draggable();

            callImg.click(() => {
                actor.toggle(200);
            });
            callImg.hover(() => {
                callImg.css("cursor", "pointer");
            });

            actor.hide();
            actor.draggable();

            initAudio(AUDIO_SRC);
            initLyricContent(ORIGIN_LYRICS, CHEER_LYRICS);

            callButton.click(() => {
                isCalling = 1 - isCalling;
                callButton.text(isCalling ? "发送中..." : "弹幕打Call");
            });

            modeButton.click(() => {
                mode = (mode + 1) % 3;
                modeButton.text(`模式${mode + 1}`);
            });
        };

        initEntrance();
    };

    // 客户端请求
    const apiClient = axios.create({
        baseURL: "https://api.live.bilibili.com",
        withCredentials: true,
    });

    // 获取勋章数据
    let medalInfos = [];
    try {
        setTimeout(async () => {
            const res = await apiClient
            .get("/xlive/web-ucenter/user/MedalWall", {
                params: {
                    target_id: window.__NEPTUNE_IS_MY_WAIFU__.userLabInfo.data.uid
                }
            });
            medalInfos = res.data.data.list;
        }, 1000);
    } catch (e) {
        console.warn("查看是否加入粉丝团时出错", e);
    }

    // 是否加入粉丝团
    const filteredMedalInfo = medalInfos.filter((item) => {
        return NANO_UID === item.medal_info.target_id;
    });
    const isNanoFan = filteredMedalInfo.length > 0;

    // 获取房间id
    const getRoomId = () => {
        if (window.__NEPTUNE_IS_MY_WAIFU__) {
            return window.__NEPTUNE_IS_MY_WAIFU__.roomInfoRes.data.room_info.room_id;
        } else {
            const url = document.URL;
            const re = /\/\d+/.exec(url);
            return re[0].substr(1);
        }
    };

    const pattern = /(room|official)(_\d+){1,2}/;
    const data = new FormData();
    const roomId = getRoomId();
    // 获取CsrfToken
    const jct = document.cookie.match(/\bbili_jct=(.+?)(?:;|$)/)[1];

    data.set("bubble", "0");
    data.set("color", "16777215");
    data.set("mode", "1");
    data.set("fontsize", "25");
    data.set("rnd", parseInt(Date.now() / 1000));
    data.set("roomid", getRoomId());
    data.set("csrf", jct);
    data.set("csrf_token", jct);

    // 发送弹幕
    const sendMessage = (message) => {
        if (data.has("dm_type")) {
            data.delete("dm_type");
        }
        data.set("msg", message);
        if (message.includes("👏")) {
            if (roomId === NANO_ROOM_ID && isNanoFan) {
                // 如果在nano直播间且已加入粉丝团则发送表情包
                data.set("dm_type", "1");
                data.set("msg", "room_22347054_1816")
            } else {
                // 否则替换掉
                data.set("msg", message.replaceAll("👏", ""));
            }
        }
        apiClient
            .post("/msg/send", data)
            .then((res) => {
            if (res.data.code === 0) {
                switch (res.data.msg) {
                    case "":
                        console.log("发送成功 - " + message);
                        break;
                    case "f":
                        console.warn("发送失败 - 包含B站屏蔽词: " + message);
                        break;
                    case "k":
                        console.warn("发送失败 - 包含直播间屏蔽词: " + message);
                        break;
                    case "same restriction":
                        console.warn("发送失败 该弹幕已被限制 请选择其它弹幕");
                        break;
                    case "max limit exceeded":
                        console.warn("发送失败 弹幕池达到上限");
                        break;
                    default:
                        console.warn("发送失败 - " + res.data.message);
                        console.warn(res)
                        console.warn(res.data)
                }
            } else {
                console.warn("发送失败 - " + res.data.message);
            }
        })
            .catch(() => {
            console.warn("发送失败 - " + message);
        });
    };

    setTimeout(() => {
        setup();
        initCheer();
    }, 2000);
})();
长期地址
遇到问题?请前往 GitHub 提 Issues,或加Q群1031348184

赞助商

Fishcpy

广告

Rainyun

注册一下就行

Rainyun

一年攒够 12 元