getLyrics method

Future<JidoujishoLyrics> getLyrics(
  1. JidoujishoLyricsParameters parameters
)

Get lyrics

Implementation

Future<JidoujishoLyrics> getLyrics(
  JidoujishoLyricsParameters parameters,
) async {
  String userAgent =
      'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36';
  String artist = Uri.encodeComponent(parameters.artist.trim());
  String title = Uri.encodeComponent(parameters.title.trim());

  late String searchUrl;
  if (artist.isEmpty) {
    searchUrl = 'https://www.google.com/search?q=$title+lyrics';
  } else {
    searchUrl = 'https://www.google.com/search?q=$title+-+$artist+lyrics';
  }

  String? text;
  bool webViewBusy = true;

  HeadlessInAppWebView webView = HeadlessInAppWebView(
    initialOptions: InAppWebViewGroupOptions(
      crossPlatform: InAppWebViewOptions(
        userAgent: userAgent,
      ),
      android: AndroidInAppWebViewOptions(
        blockNetworkImage: true,
      ),
    ),
    initialUrlRequest: URLRequest(
      url: Uri.parse(searchUrl),
    ),
    onLoadStop: (controller, uri) async {
      text = await controller.evaluateJavascript(source: '''
[...document.getElementsByClassName('ujudUb')].map((e) => {
  return e.innerText;
}).join('\\n\\n');
''');

      if (text != null && text!.trim().isEmpty) {
        text = null;
      }

      webViewBusy = false;
    },
  );

  await webView.run();

  while (webViewBusy) {
    await Future.delayed(const Duration(milliseconds: 100), () {});
  }

  if (parameters.artist.endsWith(' - Topic') && text == null) {
    return getLyrics(
      JidoujishoLyricsParameters(
        artist: parameters.artist.replaceAll(' - Topic', ''),
        title: parameters.title,
      ),
    );
  }

  if (artist.isNotEmpty && text == null) {
    String? firstResultUrl;
    bool googleWebViewBusy = true;

    HeadlessInAppWebView googleWebView = HeadlessInAppWebView(
      initialOptions: InAppWebViewGroupOptions(
        crossPlatform: InAppWebViewOptions(
          userAgent: userAgent,
        ),
        android: AndroidInAppWebViewOptions(
          blockNetworkImage: true,
        ),
      ),
      initialUrlRequest: URLRequest(
        url: Uri.parse(
            'https://google.com/search?q=$artist+$title+歌詞+site:uta-net.com/song'),
      ),
      onLoadStop: (controller, uri) async {
        firstResultUrl = await controller.evaluateJavascript(
            source:
                'document.querySelector(".yuRUbf:nth-of-type(1) > a").href');

        googleWebViewBusy = false;
      },
    );

    await googleWebView.run();

    while (googleWebViewBusy) {
      await Future.delayed(const Duration(milliseconds: 100), () {});
    }

    if (firstResultUrl != null) {
      bool utanetWebViewBusy = true;
      HeadlessInAppWebView utanetWebView = HeadlessInAppWebView(
        initialOptions: InAppWebViewGroupOptions(
          crossPlatform: InAppWebViewOptions(
            userAgent: userAgent,
          ),
          android: AndroidInAppWebViewOptions(
            blockNetworkImage: true,
          ),
        ),
        initialUrlRequest: URLRequest(
          url: Uri.parse(firstResultUrl!),
        ),
        onLoadStop: (controller, uri) async {
          text = await controller.evaluateJavascript(source: '''
[...document.getElementsByTagName('h2')].map((e) => e.remove());
var kashi = document.getElementsByClassName('row kashi')[0];
kashi.children[0].children[0].innerText;
''');

          if (text != null && text!.trim().isEmpty) {
            text = null;
          }

          utanetWebViewBusy = false;
        },
      );

      await utanetWebView.run();

      while (utanetWebViewBusy) {
        await Future.delayed(const Duration(milliseconds: 100), () {});
      }
    }
  }

  /// Try again, but without an artist. This will probably be wrong. But it's
  /// better to have tried and gotten a good result sometimes than for this
  /// to always fail just because the artist's name might make it difficult.
  if (artist.isNotEmpty && text == null) {
    return getLyrics(
      JidoujishoLyricsParameters(
        artist: '',
        title: parameters.title,
      ),
    );
  }

  return JidoujishoLyrics(
    includesArtist: artist.isNotEmpty,
    text: text,
  );
}