Skip to content
This repository has been archived by the owner on Dec 24, 2024. It is now read-only.

Commit

Permalink
Ver3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
tsukasa0220 authored Dec 11, 2022
1 parent 193fda6 commit 2262b3c
Show file tree
Hide file tree
Showing 6 changed files with 305 additions and 204 deletions.
19 changes: 19 additions & 0 deletions appsscript.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"timeZone": "Asia/Tokyo",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"dependencies": {
"libraries": [
{
"userSymbol": "Parser",
"libraryId": "1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw",
"version": "7"
},
{
"userSymbol": "Cheerio",
"libraryId": "1ReeQ6WO8kKNxoaA_O0XEQ589cIrRvEBA9qcWpNqdOP17i47u6N9M5Xh0",
"version": "14"
}
]
}
}
85 changes: 55 additions & 30 deletions calendar.gs
Original file line number Diff line number Diff line change
@@ -1,42 +1,30 @@
// googleカレンダーに追加
function createEvent(calendarId, id, titles, content, due, color) {
// 指定したgoogleカレンダーのIDを取得
let calendar = CalendarApp.getCalendarById(calendarId);

// タイトルを指定
let title = titles + '[ID:' + id + ']';

// 時間を指定
let startTime;
if (color === 2) {
startTime = new Date((due - 5400) * 1000);
} else {
startTime = new Date(due * 1000);
}
let endTime = new Date(due * 1000);

// イベントの説明
let options = {description:content}
// Googleカレンダーのイベント情報を取得する
function getCalendarEvent(user) {
// アクセス可能なカレンダーのIDを指定して、Googleカレンダーを取得

// イベントを追加
let event = calendar.createEvent(title, startTime, endTime, options);
const name = `香川大学Moodleカレンダー[${user}]`;
const options = {
timeZone: "Asia/Tokyo",
color: "#7cb342"
};

// 追加したイベントの色を指定
event.setColor(color);
}
let myCalendars = CalendarApp.getCalendarsByName(name);

// moodleのイベント情報を取得する
function getCalendarEvent(calendarId) {
// アクセス可能なカレンダーのIDを指定して、Googleカレンダーを取得
let myCalendar = CalendarApp.getCalendarById(calendarId);
if (myCalendars[0] == null) {
CalendarApp.createCalendar(name, options);
myCalendars = CalendarApp.getCalendarsByName(name);
if (DEBUG) {Logger.log("処理中:カレンダーを新しく作成します")}
}

let myCalendar = myCalendars[0];

// イベントの開始日(-7)
let startDate = new Date();
startDate.setDate(startDate.getDate() - 7);

// イベントの終了日(+28)
// イベントの終了日(+31)
let endDate = new Date();
endDate.setDate(endDate.getDate() + 28);
endDate.setDate(endDate.getDate() + 31);

// 開始日~終了日に存在するイベントを取得
let myEvent = myCalendar.getEvents(startDate, endDate);
Expand All @@ -49,3 +37,40 @@ function getCalendarEvent(calendarId) {
}
return myTitle;
}

// Googleカレンダーにイベントを追加
function createEvent(event, user) {
// 指定したgoogleカレンダーのIDを取得
let calendars = CalendarApp.getCalendarsByName(`香川大学Moodleカレンダー[${user}]`);
let calendar = calendars[0];

// タイトルを指定
let title = event.subjectTitle + '[ID:' + event.id + ']';

// 時間を指定
let startTime;
switch (event.classNum) {
case 1: startTime = new Date(event.eventtime.getFullYear(), event.eventtime.getMonth(), event.eventtime.getDate(), 8, 50, 0); break;
case 2: startTime = new Date(event.eventtime.getFullYear(), event.eventtime.getMonth(), event.eventtime.getDate(), 10, 30, 0); break;
case 3: startTime = new Date(event.eventtime.getFullYear(), event.eventtime.getMonth(), event.eventtime.getDate(), 13, 00, 0); break;
case 4: startTime = new Date(event.eventtime.getFullYear(), event.eventtime.getMonth(), event.eventtime.getDate(), 14, 40, 0); break;
case 5: startTime = new Date(event.eventtime.getFullYear(), event.eventtime.getMonth(), event.eventtime.getDate(), 16, 20, 0); break;
default : startTime = event.eventtime; break;
}
let endTime = event.eventtime;

// イベントの説明
let options = {description: event.content}

// イベントを追加
let newEvent = calendar.createEvent(title, startTime, endTime, options);

// 追加したイベントの色を指定
switch (event.component) {
case 'mod_assign' : newEvent.setColor(11); break;
case 'mod_attendance' : newEvent.setColor(10); break;
case 'mod_quiz' : newEvent.setColor(5); break;
case 'mod_questionnaire': newEvent.setColor(8); break;
default : newEvent.setColor(7); break;
}
}
230 changes: 118 additions & 112 deletions extrack.gs
Original file line number Diff line number Diff line change
@@ -1,126 +1,132 @@
// Parser: 1Mc8BthYthXx6CoIz90-JiSzSafVnT6U3t0z_W3hLTAX5ek4w0G_EIrNw
// タグを抽出
function cheerio($, className, option, val) {
const tmp = [];
$(className).each((i, elem) => {
if (option == 'attr') {tmp[i] = $(elem).attr(val)}
else if (option == 'text') {tmp[i] = $(elem).text() }
else {tmp[i] = $(elem).html() }
});
return tmp;
}

// 文字列をパースする
function parse(html, start, end) {
return Parser.data(html).from(start).to(end).iterate(); // 配列
}

function extrack(event) {
// アップデート確認
const versionUpdate = SpreadsheetApp.openById("1UcRDr9Nt9B6XY7MEydLLrCiyEagPrIK5_vG1YamuNwg").getRange("A" + (VERSION + 1)).getValue();
let preaseUpdate = "";
if (versionUpdate) {
preaseUpdate = "\n" +
'★<a href="https://github.com/tsukasa0220/MoodleCalendar">最新のバージョンがあります!!</a>\n';
function conbine(title, component, eventtype, courseid, eventlink, description, eventtime, subject) {
return `<h2><font color="darkorange">Moodleカレンダー </font><font color="#9acd32">Ver3.${VERSION}</font></h2><br>` +
      `<h4><font color="#9acd32">★</font> <font color="#ff8c00">${event_link(component, eventlink)}</font></h4><br>` +
`<b><font color="#add8e6">============================</font></b><br>` +
`<font color="#9acd32">■</font>${event_type(eventtype)}${time_change(eventtime)}<br>` +
`<font color="#9acd32">■</font>時間割名:<font color="#ff8c00"><a href="https://kadai-moodle.kagawa-u.ac.jp/course/view.php?id=${courseid}">${subject}</a></font><br>` +
`<font color="#9acd32">■</font>概要<br>` +
`${title}<br>` +
`${descript_orNull(description)}<br>` +
`<font color="#9acd32">■</font>更新日時:${time_change(new Date())}<br>` +
`<b><font color="#add8e6">============================</font></b><br>`;

// dateObjを{mm月dd日(day of week)hh時mm分}に変換
function time_change(dateObj){
let text = '';
let aryWeek = ['日', '月', '火', '水', '木', '金', '土'];
text = /*dateObj.getFullYear() + '年' + */
(dateObj.getMonth() + 1) + '月' +
dateObj.getDate() + '日' +
'(' + aryWeek[dateObj.getDay()] + ')' +
dateObj.getHours() + '時' +
dateObj.getMinutes() + '分' /*+
dateObj.getSeconds() + '秒'*/;
return text;
}

const eventArr = parse1(event, 'data-type="event"', 'class="card-link"');
// 本文があるかないか判別
function descript_orNull(description) {
let text = "";
if (String(description)) {text = `<br><font color="#9acd32">■</font>本文(プレビュー版)<br>${description}<br>`}
return text;
}

const id = parse1(event, 'data-event-id="', '"');
let title = parse1(event, '<h3 class="name d-inline-block">', '</h3>');
const due = parse1(event, '<a href="https://kadai-moodle.kagawa-u.ac.jp/calendar/view.php?view=day&amp;time=', '">');
let subject = parse1(event, '<div class="col-11"><a href="https://kadai-moodle.kagawa-u.ac.jp/course/view.php?id=', '</a></div>');
let url = parse1(event, '<div class="card-footer text-right bg-transparent">\n ', '" class="card-link">');
let description = [''];
for (let i = 0; i < eventArr.length; i++) {
if (eventArr[i].includes('<div class="description-content col-11">')) {
description[i] = parse2(eventArr[i], '<div class="description-content col-11">', '</div>');
} else {
description[i] = 'お知らせはありません';
// イベントの種類(時間用)を日本語化
function event_type (eventtype) {
switch (eventtype) {
case 'open' : return "開始日時";
case 'close' : return "終了日時";
case 'due' : return "提出期限";
case 'attendance' : return "出席期限";
default : return "活動日時";
}
}

let lors = [""];
const content = [""];
const color = [];
const subjectTitle = [""];

for (let i = 0; i < id.length; i++) {
// 取得したurlを利用して、includesで分類(提出、出席、小テスト等)とurlを作成
lors[i] = '期限';

if (url[i].includes("assign")) {                        // 課題
color[i] = 11;
url[i] = url[i] + '" class="card-link">提出物をアップロードする</a>';
subjectTitle[i] = "課題:" + subject[i].slice(6);

} else if (url[i].includes("attendance")) {                 // 出席
color[i] = 2;
url[i] = url[i] + '" class="card-link">出席登録を行う</a>';
subjectTitle[i] = "出席:" + subject[i].slice(6);

} else if (url[i].includes("quiz")) {                     // 小テスト
color[i] = 5;
url[i] = url[i] + '" class="card-link">小テストを受験する</a>';
subjectTitle[i] = "小テスト:" + subject[i].slice(6);
if (title[i].includes("開始")) {lors[i] = "開始";}

} else if (url[i].includes("questionnaire")) {                // アンケート
color[i] = 8;
url[i] = url[i] + '" class="card-link">アンケートに回答する</a>';
subjectTitle[i] = "アンケート:" + subject[i].slice(6);

} else {                                       // その他(amsplayer,chatなど)
color[i] = 7;
url[i] = url[i] + '" class="card-link">活動に移動する</a>'
subjectTitle[i] = "活動:" + subject[i].slice(6);
// 活動先のリンク先を作成
function event_link (component, eventlink) {
switch (component) {
case 'mod_assign' : return `<a href="${eventlink}">提出物をアップロードする</a>`;
case 'mod_attendance' : return `<a href="${eventlink}">出席登録を行う</a>`;
case 'mod_questionnaire': return `<a href="${eventlink}">アンケートに回答する</a>`;
case 'mod_quiz' : return `<a href="${eventlink}">テストを受験する</a>`;
default : return `<a href="${eventlink}">活動に移動する/a>`;
}

// 時間割名にURLを付与
subject[i] = '<a href="https://kadai-moodle.kagawa-u.ac.jp/course/view.php?id=' + subject[i] + '</a>';

// 本文を1つに統合
content[i] = conbibe(title[i], url[i], subject[i], description[i], due[i], lors[i], preaseUpdate);
}
return [id, subjectTitle, content, due, color];
}

// 文字列をパースする
function parse1(html, start, end) {
return Parser.data(html).from(start).to(end).iterate(); // 配列
}
function parse2(html, start, end) {
return Parser.data(html).from(start).to(end).build(); // 最初のみ
}

// UNIXを{yyyy年mm月dd日(day of week)hh時mm分ss秒}に変換
function timeChange(dateObj){
let text = '';

let aryWeek = ['日', '月', '火', '水', '木', '金', '土'];
function extrack(eventHtml) {
// eventHtmlをCheeioに渡す
const $eventLists = Cheerio.load(eventHtml);

// 直近のイベントを[class="calendar-no-results"]で判別し、ない場合は全て0で返す
if ($eventLists('.calendar-no-results').html()) {return null;}

// Cheerioで情報を抽出
const id = cheerio($eventLists, '.event' , 'attr', 'data-event-id' ); // ID
const title = cheerio($eventLists, '.event' , 'attr', 'data-event-title' ); // タイトル
const component = cheerio($eventLists, '.event' , 'attr', 'data-event-component'); // イベントの種類(リンク用)
const eventtype = cheerio($eventLists, '.event' , 'attr', 'data-event-eventtype'); // イベントの種類(時間用)
const courseid = cheerio($eventLists, '.event' , 'attr', 'data-course-id' ); // コースID
const eventlink = cheerio($eventLists, '.card-link', 'attr', 'href' ); // リンク
const unixtime = parse(eventHtml, '"https://kadai-moodle.kagawa-u.ac.jp/calendar/view.php?view=day&amp;time=', '"'); // unix時間

const description = [];
const subject = [];
const content = [];
const subjectTitle = [];
const eventtime = [];
const classNum = [];

eventHtml = cheerio($eventLists, '.event', 'html', null);

const event = [];

text = dateObj.getFullYear() + '年' + //年の取得
(dateObj.getMonth() + 1) + '月' + //月の取得 ※0~11で取得になるため+1
dateObj.getDate() + '日' + //日付の取得
'(' + aryWeek[dateObj.getDay()] + ')' + //曜日の取得 0~6で取得になるため事前に配列で設定
dateObj.getHours() + '時' + //時間の取得
dateObj.getMinutes() + '分' /*+ //分の取得
dateObj.getSeconds() + '秒'*/; //秒の取得(未使用)
for (let i = 0; i < id.length; i++) {
eventtime[i] = new Date(unixtime[i] * 1000);
description[i] = cheerio(Cheerio.load(eventHtml[i]), '.description-content', 'html', null);
subject[i] = cheerio(Cheerio.load(eventHtml[i]), `[href="https://kadai-moodle.kagawa-u.ac.jp/course/view.php?id=${courseid[i]}"]`, 'text', null);

switch (component[i]) {
case 'mod_assign' : subjectTitle[i] = "課題:" + subject[i]; break;
case 'mod_attendance' : subjectTitle[i] = "出席:" + subject[i];
classNum[i] = start_attendance(eventtime[i]); break;
case 'mod_questionnaire': subjectTitle[i] = "アンケート:" + subject[i]; break;
case 'mod_quiz' : subjectTitle[i] = "テスト:" + subject[i]; break;
default : subjectTitle[i] = "活動:" + subject[i]; break;
}

return text;
}
// 1つに統合
content[i] = conbine(title[i], component[i], eventtype[i], courseid[i], eventlink[i], description[i], eventtime[i], subject[i]);

function conbibe(title, url, subject, description, due, lors, update) {
return "=====================\n" +
"Moodleカレンダー Ver2." + VERSION + "\n" +
"=====================\n" +
update +
"\n" +
"★" + url + "\n" +
"\n" +
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
"\n" +
"■" + lors + ":" + timeChange(new Date(due * 1000)).slice(5) + "\n" +
"\n" +
"■時間割名:" + subject + "\n" +
"\n" +
"■概要" + "\n" +
"\n" +
title + "\n" +
"\n" +
"■本文" + "\n" +
"\n" +
description + "\n" +
"\n" +
"■更新日時:" + timeChange(new Date()) + "\n" +
"\n" +
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" +
"\n" +
"万一、このシステムによって利用者の不手際が発生しても一切保証を負えませんのでご了承ください。\n" +
'GitHub:<a href="https://github.com/tsukasa0220/MoodleCalendar">MoodleCalendar</a>'
}
// オブジェクト化
event[i] = {id: id[i], subjectTitle: subjectTitle[i], eventtime: eventtime[i], classNum: classNum[i], component: component[i], content: content[i]};
}
return event;

// 出席する時間を何時間目で返す
function start_attendance(dateObj) {
const timeMinute = dateObj.getHours() * 60 + dateObj.getMinutes();
if (timeMinute <= 630) {return 1;}
else if (timeMinute <= 730) {return 2;}
else if (timeMinute <= 880) {return 3;}
else if (timeMinute <= 980) {return 4;}
else if (timeMinute <= 1080) {return 5;}
else{return 0;}
}
}
Loading

0 comments on commit 2262b3c

Please sign in to comment.