Skip to content

Commit 8a6dfc3

Browse files
committed
Update
1 parent 39afd1b commit 8a6dfc3

File tree

5 files changed

+777
-741
lines changed

5 files changed

+777
-741
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ Thumbs.db
66
node_modules/
77
dist/
88

9-
# src/assets/filmdex.json はバックアップを兼ねて Git 管理にしてしまう
9+
# src/assets/filmdex.json はバックアップを兼ねて Git 管理を許可する
10+
11+
# プライベートメモ用
12+
MEMO.md

README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@
88
## Architecture
99

1010
- Angular 製のフロントエンドを GitHub Pages にデプロイしている
11-
- Angular プロジェクトからは `./src/assets/filmdex.json` に保存されている JSON ファイルを「映画情報一覧」として取得し、表示している
12-
- Git 管理されている `./src/assets/filmdex.json` ファイルはバックアップ用。最新のデータは GitHub Actions にて取得し、同パスに上書き保存・ビルド・デプロイしている
13-
- GitHub Actions にて、**個人の Google スプレッドシート**より映画情報を取得し、`./src/assets/filmdex.json` に上書き保存している
14-
- GitHub Actions は毎週月曜早朝に実行され、定期的に Google スプレッドシートの内容を GitHub Pages へと反映している他、手動実行もできるようにしてある
11+
- Angular プロジェクトからは `./src/assets/filmdex.json` に保存されている JSON ファイルを「映画情報一覧」として取得・表示している
12+
- `./src/assets/filmdex.json` の基となるデータは**個人の Google スプレッドシート (非公開)** にて管理している
13+
- 毎週日本時間の月曜早朝に GitHub Actions が実行され、Google スプレッドシートのデータを取得し GitHub Pages へと反映している
14+
- Google スプレッドシートからのデータ取得スクリプトの実体は `$ npm run fetch` (`./fetch-filmdex.js`)
15+
- 環境変数 `GOOGLE_SHEETS_URL` に API キー付きの Google スプレッドシート URL を指定して実行すると `./src/assets/filmdex.json` に上書き保存される
16+
- GitHub Actions での実行時は `gh-pages` ブランチのみ更新しており `master` ブランチへのコミットは行っていない
17+
- GitHub Actions は手動実行もできる
18+
- `master` ブランチにコミットされている `./src/assets/filmdex.json` は手動バックアップを兼ねている。不定期に本スクリプトをローカル実行して手動コミットしておくこと
19+
- 開発やローカル実行に関する情報は適宜 `./MEMO.md` (Git 管理対象外) に記載しておけるようにしてある
1520

1621

1722
## Note : Initial Setup

fetch-filmdex.js

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const distAssetsFilePath = path.resolve(distAssetsDirectoryPath, jsonFileNa
2929
const json = parseToJson(result);
3030

3131
// 見出し行からフォーマットをチェックする
32-
const header = json.values.shift(); // データの先頭1行が見出し・ココで `json.values` の先頭行を削除している
32+
const header = json.values.shift(); // データの先頭1行が見出し・ココで json.values の先頭行が削除される
3333
validateHeaderColumns(header);
3434

3535
// 映画情報一覧に変換・ソートする
@@ -91,7 +91,7 @@ async function fetch(url) {
9191
return result;
9292
}
9393
catch(error) {
94-
console.error('Failed To Request');
94+
console.error('Failed To Request', error);
9595
throw error;
9696
}
9797
}
@@ -129,11 +129,11 @@ function parseToJson(text) {
129129
* 取得したスプレッドシートの1行目を確認し、正しいフォーマットかどうか確認する
130130
*
131131
* @param {Array<string>} header ヘッダ行
132-
* @return {boolean} 列数・列名・列順が全て正しければ true
132+
* @return {boolean} 列名・列順が全て正しければ true
133133
* @throws 不正なフォーマットだった場合
134134
*/
135135
function validateHeaderColumns(header) {
136-
/** 見出し行データとして想定する文言 */
136+
/** 見出し行として想定する列順と文言・現状は英語表記が合致する想定 */
137137
const expectedHeader = [
138138
['Published Year', '公開年' ],
139139
['Title' , '原題' ],
@@ -142,20 +142,18 @@ function validateHeaderColumns(header) {
142142
['Review' , '感想' ],
143143
['Casts' , 'キャスト'],
144144
['Staffs' , 'スタッフ'],
145-
['Tags' , 'タグ' ]
145+
['Tags' , 'タグ' ] // コレ以降に列が存在しても無視する
146146
];
147147

148-
// 列数が一致していること
149-
if(expectedHeader.length !== header.length) {
150-
console.error(`Number Of Header Columns Is Invalid`, { expectedHeaderLength: expectedHeader.length, headerLength: header.length, header: header });
151-
throw new Error('Number Of Header Columns Is Invalid');
152-
}
153-
154-
// 全ての列名について想定文言のいずれかに合致すること
155-
const isValid = header.every((columnName, index) => {
156-
return expectedHeader[index].some((expectedColumnName) => columnName === expectedColumnName);
148+
// ヘッダ行の各列について想定文言のいずれかに合致すること
149+
const isValid = expectedHeader.every((expectedColumnValues, index) => {
150+
const columnValue = header[index];
151+
return expectedColumnValues.some((expectedColumnValue) => columnValue === expectedColumnValue);
157152
});
158-
if(!isValid) throw new Error('Invalid Header Columns');
153+
if(!isValid) {
154+
console.error('Invalid Header Columns', header);
155+
throw new Error('Invalid Header Columns');
156+
}
159157

160158
return isValid;
161159
}
@@ -168,26 +166,27 @@ function validateHeaderColumns(header) {
168166
*/
169167
function convertToFilms(values) {
170168
return values.map((row, index) => {
171-
// 「公開年」と「原題」は必須とする・後続が空値のみの列のみだと配列の要素ごと少なくなる
169+
// 「公開年」と「原題」の2列は必須とする・後続列が空値のみだと配列の要素ごと少なくなる
172170
if(row.length < 2) {
173171
console.error('Invalid Row Data', { index, row });
174172
throw new Error('Invalid Row Data');
175173
}
176-
// 1列目のデータが数値型に変換できなければ不正値とみなす
177-
if(Number.isNaN(Number(row[0]))) {
174+
// 1列目のデータ (公開年) が数値型に変換できなければ不正値とみなす
175+
const publishedYear = Number(row[0]);
176+
if(Number.isNaN(publishedYear)) {
178177
console.error('Invalid Published Year Data', { index, row });
179178
throw new Error('Invalid Published Year Data');
180179
}
181180

182-
return { // Film クラス相当の連想配列にする・空白や改行は除去する
183-
publishedYear: Number(row[0]),
184-
title : row[1] == null ? '' : String(row[1]).trim().replace((/\n/gu), ''),
185-
japaneseTitle: row[2] == null ? '' : String(row[2]).trim().replace((/\n/gu), ''),
186-
scenario : row[3] == null ? '' : String(row[3]).trim().replace((/\n/gu), ''),
187-
review : row[4] == null ? '' : String(row[4]).trim().replace((/\n/gu), ''),
188-
casts : row[5] == null ? '' : String(row[5]).trim().replace((/\n/gu), ''),
189-
staffs : row[6] == null ? '' : String(row[6]).trim().replace((/\n/gu), ''),
190-
tags : row[7] == null ? '' : String(row[7]).trim().replace((/\n/gu), '')
181+
return { // Film クラス相当の連想配列にする
182+
publishedYear: publishedYear,
183+
title : convertToOneLineString(row[1]),
184+
japaneseTitle: convertToOneLineString(row[2]),
185+
scenario : convertToOneLineString(row[3]),
186+
review : convertToOneLineString(row[4]),
187+
casts : convertToOneLineString(row[5]),
188+
staffs : convertToOneLineString(row[6]),
189+
tags : convertToOneLineString(row[7])
191190
};
192191
})
193192
.sort((filmA, filmB) => {
@@ -200,6 +199,17 @@ function convertToFilms(values) {
200199
// 同一値なら 0 を返す
201200
return 0;
202201
});
202+
203+
/**
204+
* セルの値を文字列に変換し空白や改行を除去する
205+
* Google スプレッドシート API はセルの値を必ず文字列型で返すようだが念のため String() で文字列化しておく
206+
*
207+
* @param {string|number|null|undefined} value 値
208+
* @return {string} 値が存在しない場合は空文字・値が存在すれば空白をトリムし改行を除去した文字列
209+
*/
210+
function convertToOneLineString(value) {
211+
return value == null ? '' : String(value).trim().replace((/\n/gu), '');
212+
}
203213
}
204214

205215
/**

0 commit comments

Comments
 (0)