Allen_Jeo

Allen_Jeo

重邮コース表のカレンダーインポート

現在、重郵の時間割を確認するには、掌上重郵アプリと We 重郵微信ミニプログラムを通じて行うことができますが、これらのアプリは授業があるときに事前通知を行うことができません。したがって、これらのアプリのインターフェースを通じて時間割データを提供し、一般的なiCalendar形式に変換してカレンダーにインポートする方が良いでしょう。そうすれば、システムレベルのカレンダー通知を体験できます。

以前、Python 版のCQUPT-icsが重郵の先輩によって作成されましたが、現在これらのデータソースのインターフェースは変更されており、正常に使用できなくなっています。

そのため、私は上記の目標を達成するために新しいプロジェクトを書くことにしました。先輩のプロジェクトの考え方に従って、書き直し RIIR (Rewrite It In Rust) を行います。

新しいプロジェクトのアドレス:https://github.com/jizizr/cqupt-ics-rs プロジェクトのソースコードはここにあります。

使用アドレス:https://cqupt.op.wiki/ このプロジェクトを使用するにはここをクリックしてください。

image

基本的に以前の Python 版の機能を実現しました。さらに、調休の自動授業調整も実装しました。これにより、休暇中に授業の通知を受け取ることを避け、今日の調休で授業があることを忘れることがなくなります(重郵の公式時間割は休暇に応じて変更されないため、自分で調休のスケジュールを確認する必要があります)。

もちろん、単にリンクをつなげて購読するだけでは十分ではないので、フロントエンドの使用インターフェース(AI によるもの)を作成する必要があります。これにより、このプロジェクトを友好的に使用できるようになるはずです。学校は夜に時間割の確認を閉じるため、0 時から 7 時の間は時間割を確認できないのは正常な現象です

PS: ワンクリックインポートの実装は Android と Apple シリーズのシステムのみ対応しています。他のシステムは ICS 購読をサポートするカレンダーにリンクをコピーして追加してください。

本来は webcal:// でカレンダー追加にジャンプする予定でしたが、理論的には webcal:// プロトコルヘッダーのジャンプは基本的にすべてのシステムで実装されていますが、Apple(macOS、iOS)以外の他のシステムでは、実際に提供されるカレンダーソフトウェアが異なるため、具体的には大きな差異があり、奇妙な問題が発生することがほとんどです。したがって、Apple 専用に提供し、Android は intent:// を使用してシステムカレンダーにジャンプします。したがって、Apple シリーズのシステムと Android のみが実装されています。

より良い実装があれば PR を歓迎します。バグがあれば issue を提起してください。

最後に、インポートの効果を見てみましょう。

image

国慶節(休)にはすべての授業が削除され、国慶節(班)には対応する調休の授業があります。

Screenshot_2025-10-20-19-09-38-072_com.google.android.calendar-edit

携帯電話での効果

新しいプロバイダーソースを追加するには、単にトレイトを実装すれば良いだけです(非常に簡単

#[async_trait]
pub trait Provider: Send + Sync {
    /// このプロバイダーのトークンタイプ
    type Token: Send + Sync + Serialize + DeserializeOwned;
    type ContextType: Send + Sync;
    /// プロバイダーの名前
    fn name(&self) -> &str;

    /// プロバイダーの説明
    fn description(&self) -> &str;

    /// このプロバイダーのタイムゾーンを取得
    ///
    /// このプロバイダーが時間計算に使用するタイムゾーンを返します。
    /// これは、すべてのプロバイダー操作で一貫したタイムゾーン処理を確保するために使用されます。
    /// プロバイダーのタイムゾーン
    fn timezone(&self) -> FixedOffset;

    /// 認証してトークンを取得
    /// トークンを取得する方法
    async fn authenticate<'a, 'b>(
        &'a self,
        context: ParamContext<'b, Self::ContextType>,
        request: &CourseRequest,
    ) -> Result<Self::Token>;

    /// 既存のトークンを検証
    /// トークンが有効かどうかを検証
    async fn validate_token(&self, token: &Self::Token) -> Result<bool>;

    /// トークンを更新
    /// トークンを更新する方法(プロバイダーが存在しない場合は直接Errを返す)
    async fn refresh_token(&self, token: &Self::Token) -> Result<Self::Token>;

    /// トークンを使用してコースを取得
    /// request.semesterはこのメソッドを呼び出す前にSomeである必要があります
    /// crate::providers::Wrapperを使用すると、semesterがSomeであることが保証されます
    /// コースデータを取得する方法
    async fn get_courses<'a, 'b>(
        &'a self,
        context: ParamContext<'b, Self::ContextType>,
        request: &mut CourseRequest,
        token: &Self::Token,
    ) -> Result<CourseResponse>;

    /// 学期の開始日を取得
    /// request.semesterがNoneの場合にget_coursesの前に呼び出されます
    /// crate::providers::Wrapperを使用すると、request.semesterがNoneの場合にこのメソッドが自動的に呼び出されます
    /// 必要に応じて中間データを保存するためにコンテキストを使用できます
    /// 学期開始日を取得する方法
    async fn get_semester_start<'a, 'b>(
        &'a self,
        context: ParamContext<'b, Self::ContextType>,
        request: &mut CourseRequest,
        token: &Self::Token,
    ) -> Result<chrono::DateTime<FixedOffset>>;

    /// トークンのTTL
    /// トークンの有効期限を返し、キャッシュを制御するために使用します
    fn token_ttl(&self) -> Duration {
        Duration::from_secs(3600 * 24) // デフォルトは24時間
    }
}
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。