lichess_client_dio 0.0.9 copy "lichess_client_dio: ^0.0.9" to clipboard
lichess_client_dio: ^0.0.9 copied to clipboard

Lichess HTTP client based on Dio. Cross-platform API wrapper written in pure Dart.

example/lichess_client_dio.dart

import 'dart:async';
import 'dart:io';

import 'package:dotenv/dotenv.dart';
import 'package:lichess_client_dio/lichess_client_dio.dart';

Future<void> main(List<String> arguments) async {
  final DotEnv env = DotEnv()..load();

  final String? token = env['LICHESS_PERSONAL_TOKEN'];

  assert(
    token != null,
    'You need to define your personal token inside the file .env, use .env.example as template.',
  );

  final LichessClient lichess = LichessClientDio.create(accessToken: token);

  await _displayLoggedUserEmail(lichess);
  await _displayLoggedUserProfile(lichess);
  await _displayLoggedUserPreferences(lichess);
  await _displayLoggedUserFollows(lichess);
  await _displayLoggedUserKidModeStatus(lichess);
  await _toggleAndDisplayLoggedUserKidModeStatus(lichess);
  await _displayLiveStreamers(lichess);
  await _fetchAndDisplaySeveralUsers(lichess);
  await _fetchAndDisplayRealTimeStatusOfSeveralUsers(lichess);
  await _displayAutocompleteUsernameResultsFor('alexr', lichess);
  await _displayAutocompleteUserResultsFor('alexr', lichess);
  await _displayRatingHistoryOf('riccardocescon', lichess);
  await _displayUserPublicData('riccardocescon', lichess);
  await _displayTeamInfo('group-test', lichess);
  await _displayMostPopularTeams(lichess);
  await _displayUserTeams('riccardocescon', lichess);
  await _displayTeamSearchResultsFor('test', lichess);
  await _displayTeamMembers('lichess-swiss', lichess);
  await _displayTeamMembersUsingBackpressure('lichess-swiss', lichess);
  await _displayCurrentTvGames(lichess);
  await _startStreamingTheCurrentTvGameForTheNextFewMoves(lichess);
  await _getGameModeLeaderboard(
    <PerfType>[
      PerfType.rapid,
      PerfType.atomic,
      PerfType.blitz,
      PerfType.bullet,
    ],
    lichess,
  );
  await _displayUserRecentGames('riccardocescon', lichess);
  await _displayInfoFromArbitraryGame('E1sx21nN', lichess);

  // TODO: lichess.teams.join
  // TODO: lichess.teams.leave
  // TODO: lichess.teams.getJoinRequests
  // TODO: lichess.teams.kickMember

  await _displayDailyPuzzle(lichess);
  await _displayPuzzleById('K69di', lichess);
  await _displayMyPuzzleActivity(lichess, max: 10);
  await _displayMyPuzzleDashboard(lichess);

  await lichess.close();
}

Future<void> _delay(int seconds) async {
  return Future<void>.delayed(Duration(seconds: seconds));
}

Future<void> _startStreamingTheCurrentTvGameForTheNextFewMoves(
  LichessClient lichess, {
  int movesCount = 10,
}) async {
  _header('lichess.tv.streamCurrentTvGame');

  final Stream<LichessTvGameSummary> currentTvGameStream =
      lichess.tv.streamCurrentTvGame().take(movesCount);

  bool first = true;

  await for (final LichessTvGameSummary tvGameSnapshot in currentTvGameStream) {
    if (first) {
      first = false;
      _print('Black: ${tvGameSnapshot.data?.blackPlayer?.user?.id}');
      _print('White: ${tvGameSnapshot.data?.whitePlayer?.user?.id}');
    }

    _print('Current game FEN: ${tvGameSnapshot.data?.fen}');
    _print('Orientation: ${tvGameSnapshot.data?.orientation}');
  }

  _footer('lichess.tv.streamCurrentTvGame');
}

Future<void> _displayInfoFromArbitraryGame(
  String gameId,
  LichessClient lichess,
) async {
  _header('lichess.games.exportGame');

  final LichessGame game = await lichess.games.exportGame(gameId: gameId);

  _footer(
    '${game.players.black?.user?.id} (Black) vs ${game.players.white?.user?.id} (White)',
  );
  _print('Speed: ${game.speed}');
  _print('Perf type: ${game.perf}');
  _print('Initial fen: ${game.initialFen}');
  _print('Moves: ${game.moves}');
  _print('Winner: ${game.winner?.raw}');
  _print('Rated: ${game.rated}');
  _print('Status: ${game.status}');
  _print('Game Id: ${game.id}');
  _print('Clock: ${game.clock}');

  _footer('lichess.games.exportGame');
}

Future<void> _displayUserRecentGames(
  String username,
  LichessClient lichess,
) async {
  _header('lichess.games.exportGamesOfUser');

  final Stream<LichessGame> userGames =
      lichess.games.exportGamesOfUser(username: username, max: 10);

  await for (final LichessGame game in userGames) {
    _footer(
      '${game.players.black?.user?.id} (Black) vs ${game.players.white?.user?.id} (White)',
    );
    _print('Speed: ${game.speed}');
    _print('Perf type: ${game.perf}');
    _print('Initial fen: ${game.initialFen}');
    _print('Moves: ${game.moves}');
    _print('Winner: ${game.winner?.raw}');
    _print('Rated: ${game.rated}');
    _print('Status: ${game.status}');
    _print('Game Id: ${game.id}');
    _print('Clock: ${game.clock}');
  }

  _footer('lichess.games.exportGamesOfUser');
}

Future<void> _displayCurrentTvGames(LichessClient lichess) async {
  _header('lichess.tv.getCurrentTvGames');

  final List<LichessTvGameBasicInfo> tvGames =
      await lichess.tv.getCurrentTvGames();

  for (final LichessTvGameBasicInfo tvGameBasicInfo in tvGames) {
    _footer('Channel: ${tvGameBasicInfo.channel}');
    _print('user.name: ${tvGameBasicInfo.user?.name}');
    _print('user.id: ${tvGameBasicInfo.user?.id}');
    _print('user.patron: ${tvGameBasicInfo.user?.patron}');
    _print('user.title: ${tvGameBasicInfo.user?.title}');
    _print('game rating: ${tvGameBasicInfo.rating}');
    _print('game id: ${tvGameBasicInfo.gameId}');
  }

  _footer('lichess.tv.getCurrentTvGames');
}

Future<void> _displayTeamMembersUsingBackpressure(
  String teamId,
  LichessClient lichess,
) async {
  late final StreamSubscription<User> subscription;
  late final Stream<User> teamMembersStream;

  _header('lichess.teams.getMembers');

  teamMembersStream = lichess.teams.getMembers(teamId: teamId);

  _print('Members: ');

  final Completer<void> completer = Completer<void>();

  final List<User> users = <User>[];

  Future<void> cancel() async {
    _print('Canceling subscription...');
    await subscription.cancel();
    completer.complete();
  }

  subscription = teamMembersStream.listen(
    (User user) async {
      users.add(user);

      _print('${user.id} (name: ${user.name})');

      if (users.length % 20 == 0) {
        if (users.length >= 30) {
          _print('Got 60th user loaded, stopping...');
          // When we reach the 60th user loaded, stop.
          await cancel();
        } else {
          _print('Pausing for 10 secs...');
          // When user list reaches the 20|40th user loaded, pause for 10 seconds.
          subscription.pause();
          await _delay(10);
          _print('Resuming again...');
          subscription.resume();
        }
      }
    },
    onDone: cancel,
    cancelOnError: true,
    onError: (Object error, StackTrace stackTrace) {
      _print('Error $error');
      _print('Stack trace: $stackTrace');
      cancel();
    },
  );

  await completer.future;

  _footer('lichess.teams.getMembers');
}

Future<void> _displayTeamMembers(
  String teamId,
  LichessClient lichess,
) async {
  _header('lichess.teams.getMembers');

  final Stream<User> teamMembersStream =
      lichess.teams.getMembers(teamId: teamId);

  final List<User> members = await teamMembersStream.take(30).toList();

  _footer('First ${members.length} members of $teamId');

  _print('Members: ${members.map((User member) => member.id).join(', ')}');

  _footer('lichess.teams.getMembers');
}

Future<void> _displayTeamSearchResultsFor(
  String text,
  LichessClient lichess,
) async {
  _header('lichess.teams.getByUser');
  final PageOf<Team> query = await lichess.teams.search(text: text);

  _footer('Search results for $text:');

  _footer('Query info');

  _print('query.currentPage: ${query.currentPage}');
  _print('query.maxPerPage: ${query.maxPerPage}');
  _print('query.nbPages: ${query.nbPages}');
  _print('query.nbResults: ${query.nbResults}');
  _print('query.nextPage: ${query.nextPage}');
  _print('query.previousPage: ${query.previousPage}');

  _footer('End query info');

  for (final Team team in query.currentPageResults ?? <Team>[]) {
    _footer('Start team entry');
    _printTeamInfo(team);
    _footer('End of entry');
  }

  _footer('lichess.teams.getByUser');
}

Future<void> _displayUserTeams(String username, LichessClient lichess) async {
  _header('lichess.teams.getByUser');
  final List<Team> userTeams =
      await lichess.teams.getByUser(username: username);

  _footer('Teams that $username is member of:');

  for (final Team team in userTeams) {
    _printTeamInfo(team);
    _footer('End of entry');
  }

  _footer('lichess.teams.getByUser');
}

void _printTeamInfo(Team team) {
  _print('Team id: ${team.id}');
  _print('Team name: ${team.name}');
  _print('Team description: ${team.description}');
  _print('Team leader: ${team.leader?.id}');
  _print('Number of members: ${team.nbMembers}');
  _print('Location: ${team.location}');
  _print('Is team open? ${team.open}');
}

Future<void> _displayTeamInfo(String teamId, LichessClient lichess) async {
  _header('lichess.teams.getById');
  final Team team = await lichess.teams.getById(teamId);

  _printTeamInfo(team);

  _footer('lichess.teams.getById');
}

Future<void> _displayMostPopularTeams(LichessClient lichess) async {
  _header('lichess.teams.getPopular');

  // you can also do pagination by providing [page] param.
  final PageOf<Team> mostPopularTeams = await lichess.teams.getPopular();

  for (final Team team in mostPopularTeams.currentPageResults ?? <Team>[]) {
    _printTeamInfo(team);
    _footer('End of entry');
  }

  _footer('lichess.teams.getPopular');
}

Future<void> _displayUserPublicData(
  String username,
  LichessClient lichess,
) async {
  _header('lichess.users.getPublicData');
  final User user = await lichess.users.getPublicData(username: username);
  _print('Public data of $username: $user');
  _footer('lichess.users.getPublicData');
}

Future<void> _getGameModeLeaderboard(
  List<PerfType> perfTypes,
  LichessClient lichess,
) async {
  _header('lichess.users.getPerfTypeLeaderboard');

  for (final PerfType perfType in perfTypes) {
    _footer('$perfType');

    final List<User> users =
        await lichess.users.getPerfTypeLeaderboard(perfType: perfType);

    int i = 0;

    for (final User user in users) {
      _print('${++i}th: ${user.id}');
    }
  }

  _footer('lichess.users.getPerfTypeLeaderboard');
}

Future<void> _displayRatingHistoryOf(
  String username,
  LichessClient lichess,
) async {
  final List<RatingHistory> ratingHistory =
      await lichess.users.getRatingHistory(username: username);

  _header('lichess.users.getRatingHistory');

  for (final RatingHistory ratingHistory in ratingHistory) {
    _footer('${ratingHistory.name ?? 'Unnamed category'} stats for $username');

    if (ratingHistory.info == null) {
      _print('No data is available $username');
    } else if (ratingHistory.info!.isEmpty) {
      _print('Not enough data for $username');
    } else {
      final RatingHistoryEntry newest = ratingHistory.info!.newest;
      final RatingHistoryEntry older = ratingHistory.info!.oldest;

      final RatingHistoryEntry highest = ratingHistory.info!.highest;
      final RatingHistoryEntry lowest = ratingHistory.info!.lowest;

      final int ratingDelta = newest.rating - older.rating;
      final Duration timeDelta = Duration(
        milliseconds: newest.date.millisecondsSinceEpoch -
            older.date.millisecondsSinceEpoch,
      );

      _print('Current rating: ${newest.rating}');
      _print('Highest rating: ${highest.rating}');
      _print('Lowest rating: ${lowest.rating}');
      _print('Rating delta: $ratingDelta');
      _print('Account life time in days: ${timeDelta.inDays}');
    }

    _footer(ratingHistory.name ?? 'Unnamed category');
  }

  _footer('lichess.users.getRatingHistory');
}

Future<void> _displayAutocompleteUsernameResultsFor(
  String username,
  LichessClient lichess,
) async {
  final List<String> results =
      await lichess.users.searchNamesByTerm(term: 'alexr');

  _header('lichess.users.autocompleteUsernames');
  _print(
    'Autocomplete results for [$username]: ${results.map((String e) => e).join(', ')}',
  );
  _footer('lichess.users.autocompleteUsernames');
}

Future<void> _displayAutocompleteUserResultsFor(
  String username,
  LichessClient lichess,
) async {
  final List<User> results = await lichess.users.searchByTerm(term: 'alexr');

  _header('lichess.users.autocomplete');
  _print(
    'Autocomplete object results for [$username]: ${results.map((User e) => '${e.id} (object)').join(', ')}',
  );
  _footer('lichess.users.autocomplete');
}

Future<void> _fetchAndDisplayRealTimeStatusOfSeveralUsers(
  LichessClient lichess,
) async {
  final List<RealTimeUserStatus> users = await lichess.users.getRealTimeStatus(
    ids: <String>['chess-network', 'alexrintt', 'riccardocescon'],
  );

  _header('lichess.users.getRealTimeStatus');
  _print(
    'Fetched users: ${users.map((RealTimeUserStatus e) => '${e.name} (${e.online ? 'Online' : 'Offline'})').join(', ')}',
  );
  _footer('lichess.users.getRealTimeStatus');
}

Future<void> _fetchAndDisplaySeveralUsers(LichessClient lichess) async {
  final List<User> users = await lichess.users
      .getManyById(ids: <String>['alexrintt', 'riccardocescon']);

  _header('lichess.users.getManyById');
  _print(
    'Fetched users: ${users.map((User e) => '${e.id} (${e.url})').join(', ')}',
  );
  _footer('lichess.users.getManyById');
}

Future<void> _displayLiveStreamers(LichessClient lichess) async {
  final List<User> liveStreamers = await lichess.users.getLiveStreamers();

  _header('lichess.users.getLiveStreamers');
  _print(
    'Live streamers: ${liveStreamers.map((User e) => '${e.id} (${e.url})').join(', ')}',
  );
  _footer('lichess.users.getLiveStreamers');
}

Future<void> _displayLoggedUserKidModeStatus(LichessClient lichess) async {
  final bool isKidMode = await lichess.account.getKidModeStatus();
  _header('lichess.account.getKidModeStatus');
  _print('isKidMode: $isKidMode');
  _footer('lichess.account.getKidModeStatus');
}

Future<void> _toggleAndDisplayLoggedUserKidModeStatus(
  LichessClient lichess,
) async {
  _header('lichess.account.setMyKidModeStatus');
  _print('Toggling kid mode status...');

  bool isKidMode = await lichess.account.getKidModeStatus();
  await lichess.account.setMyKidModeStatus(enableKidMode: !isKidMode);
  isKidMode = await lichess.account.getKidModeStatus();

  _print('New kid mode status: $isKidMode');
  _footer('lichess.account.getMyKidModeStatus');
}

Future<void> _displayLoggedUserPreferences(LichessClient lichess) async {
  final UserPreferences preferences = await lichess.account.getMyPreferences();
  _header('lichess.account.getMyPreferences');
  _print('Preference: $preferences');
  _footer('lichess.account.getMyPreferences');
}

Future<void> _displayLoggedUserEmail(LichessClient lichess) async {
  final String email = await lichess.account.getEmailAddress();
  _header('lichess.account.getMyEmailAddress');
  _print('My email address is: $email');
  _footer('lichess.account.getMyEmailAddress');
}

Future<void> _displayLoggedUserProfile(LichessClient lichess) async {
  final User user = await lichess.account.getProfile();
  _header('lichess.account.getMyProfile');
  _print('My ID is: ${user.id}');
  _print('Bio: ${user.profile?.bio}');
  _print(
    'My account was created at: ${DateTime.fromMillisecondsSinceEpoch(user.createdAt!)}',
  );
  _footer('lichess.account.getMyProfile');
}

Future<void> _displayLoggedUserFollows(LichessClient lichess) async {
  _header('lichess.relations.getFollowing');
  final List<User> follows = await lichess.relations.getFollowing();
  _print(
    'Logged user follows: ${follows.map((User e) => e.id).join(', ')}',
  );
  _footer('lichess.relations.getFollowing');
}

Future<void> _displayDailyPuzzle(LichessClient lichess) async {
  _header('lichess.puzzle.getDailyPuzzle');
  final LichessPuzzle puzzle = await lichess.puzzles.getDailyPuzzle();
  _print('Puzzle ID: ${puzzle.puzzle?.id} with Pgn: ${puzzle.game?.pgn}');
  _footer('lichess.puzzle.getDailyPuzzle');
}

Future<void> _displayPuzzleById(String id, LichessClient lichess) async {
  _header('lichess.puzzle.getPuzzleById');
  final LichessPuzzle puzzle = await lichess.puzzles.getPuzzleById(id: id);
  _print('Puzzle ID: ${puzzle.puzzle?.id} with Pgn: ${puzzle.game?.pgn}');
  _footer('lichess.puzzle.getPuzzleById');
}

Future<void> _displayMyPuzzleActivity(LichessClient lichess, {int? max}) async {
  _header('lichess.puzzle.getMyPuzzleActivity');
  await for (final LichessPuzzleActivity data
      in lichess.puzzles.getPuzzleActivity(max: max)) {
    _print('Puzzle activity: ${data.id} : ${data.puzzleRating}');
  }
  _footer('lichess.puzzle.getMyPuzzleActivity');
}

Future<void> _displayMyPuzzleDashboard(LichessClient lichess) async {
  _header('lichess.puzzle.getMyPuzzleDashboard');
  final LichessPuzzleDashboard dashboard =
      await lichess.puzzles.getPuzzleDashboard();
  _print('Puzzle dashboard: ${dashboard.toJson()}');
  _footer('lichess.puzzle.getMyPuzzleDashboard');
}

bool _first = true;

void _header(String message) {
  stdout.writeln('${_first ? '' : '\n\n'}${'-' * 10} [$message] ${'-' * 10}');
  _first = false;
}

void _footer(String message) {
  stdout.writeln('${'-' * 10} [$message] ${'-' * 10}');
}

void _print(String message) {
  stdout.writeln(message);
}
0
likes
160
pub points
39%
popularity

Publisher

verified publisheralexrintt.io

Lichess HTTP client based on Dio. Cross-platform API wrapper written in pure Dart.

Homepage
Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

Funding

Consider supporting this project:

donate.alexrintt.io
github.com
www.patreon.com

License

MIT (license)

Dependencies

dio, freezed_annotation, json_annotation, lichess_client, ndjson, retrofit

More

Packages that depend on lichess_client_dio