masalibの日記

システム開発、運用と猫の写真ブログです

今週読んだ漫画…『姉なるもの1〜2巻』

満喫の棚に並んでいて、おっぱいに負けて選んだ

今北産業(3行でまとめると)

1・親なしの14歳が悪魔を召喚して願ったのがお姉ちゃんがほしい
24ページより引用

2・悪魔も人間や姉になる事を楽しんでいる
35ページより引用

3・おっぱいがデカすぎ!!
29ページより引用

作者

飯田ぽち。さん
通常攻撃が全体攻撃で二回攻撃のお母さんは好きですか」の
イラストを書いている人

コミケで同人のエロ系を書いていたっぽい

www.pixiv.net



どの絵も髪の毛が綺麗!!
女性作家ならではですね



画像はTwitterより引用しています

firebase functions単位にファイル分割

masalib.hatenablog.com

前回、サムネイルをつくるfunctionと翻訳するfunctionを作ったが
2つのfunctionを1つのindex.jsに書くという通常の開発ではありえない事をした
node.jsの初心者なんでトライアンドエラーで分割をした

github.com


いけていない所があります

try {
	admin.initializeApp(functions.config().firebase);
} catch (err) {
	//console.error('Firebase initialization error', err.stack)
}

トライ・アンド・キャッチしている所です

別の所で定義するとエラーでうごかず、
trycathcにしないとデプロイができない

デプロイのエラー

Error: The default Firebase app already exists. This means you called initializeApp() more than once without providing an app name as the second argument. In most cases you only need to call initializeApp() once. But if you do want to initialize multiple apps, pass a second argument to initializeApp() to give each app a unique name.
    at FirebaseAppError.FirebaseError [as constructor] (/tmp/fbfn_11222Qg6NpvXGscFd/node_modules/firebase-admin/lib/utils/error.js:25:28)
    at new FirebaseAppError (/tmp/fbfn_11222Qg6NpvXGscFd/node_modules/firebase-admin/lib/utils/error.js:70:23)
    at FirebaseNamespaceInternals.initializeApp (/tmp/fbfn_11222Qg6NpvXGscFd/node_modules/firebase-admin/lib/firebase-namespace.js:38:23)
    at FirebaseNamespace.initializeApp (/tmp/fbfn_11222Qg6NpvXGscFd/node_modules/firebase-admin/lib/firebase-namespace.js:237:30)
    at Object.<anonymous> (/tmp/fbfn_11222Qg6NpvXGscFd/generateThumbnail/index.js:6:8)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/tmp/fbfn_11222Qg6NpvXGscFd/index.js:9:29)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at /usr/lib/node_modules/firebase-tools/lib/triggerParser.js:18:11
    at Object.<anonymous> (/usr/lib/node_modules/firebase-tools/lib/triggerParser.js:32:3)

う~ん・・・
trycatchは最終手段に近いのいずれ治したい


イベントがすべてのフォルダで取得しているみたいなので
そこも特定のフォルダのみのイベントにしたい

module.exports = functions.storage.object().onChange(event => {

今はファイルパスをチェックして処理を終了させている
(間違えているきがする・・・)

  const filePath = event.data.name;
  // filePath uploads以外はサムネイルを作らない
  if (!filePath.startsWith('uploads')) {
    console.log('This is not "uploads/" path.');
    console.log(filePath);
    return;
  }

node.jsの経験がないから、本当に時間がかかる
楽しいからいいですけど〜♪

firebase functionsにはcronがない

定期的にfunctionsを実行したかったが
サンプルをみた所ないらしい
github.com

しかも外部のサービスを記載していた

https://www.setcronjob.com/
https://cron-job.org/
https://www.easycron.com/
https://zapier.com/zapbook/webhook/

T_T
google先生っぽくないな~

無料でやるならGoogle Apps Scriptでおこなうが楽かも
www.sakana.tech

ちなみにAWS Lambdaにある
docs.aws.amazon.com

対抗しているなら作ってくださいよ

モンスト 物語シリーズコラボはひどかった

モンストで物語シリーズのコラボがありました

怒られるかもしれませんが

歴代のコラボの中で酷いコラボだったと思う

 

1・コラボガチャがない

物語シリーズが好きな私はコンプしたいのですが

コラボガチャがない

 

10連ガチャのおまけで戦場ヶ原ひだぎ(ガハラさん)と忍野忍がでる仕様でした

 

youtuberじゃない無課金ユーザーの私は

10連ガチャなんて1ヶ月に1,2回ぐらいしかひけません

それもおまけが絶対にでる仕様ではない

 

ガチャの動画をみていると

30連に1体でる感じでした

 

10連は約3,000円なので

18,000円を突っ込まないといけない仕様だった

 

奇跡的に10連で忍野忍がでたが

戦場ヶ原ひだぎは諦めた

 

2・運極がめちゃくちゃ時間がかかる

 ドラえもんとかハガレンとか色々なコラボをやったが

運極は1キャラあたりクエストを40~50回ぐらいやればいけます

(対応キャラ次第)

 

今回の酷い所は

八九寺真宵の所です


クリアボーナスで64体、メダル引き換えで35体入手すれば運極を作ることができる。
メダルは計70万枚必要なため、メダル集めが苦でなければ運極を目指そう。

【モンスト】化物語シリーズコラボのガチャ当たり一覧とおすすめ運極 - GameWith

より引用

 

メダルが70万枚です

 

ぼっちの自分が1クエストでもらえるコインは2000枚です

つまり約350回ぐらいのクエストクリアが必要になる

 

8/8(火)12:00〜9/2(土)11:59なので

1日あたり13回以上クリアしないといけないのです

 

なでこスネイク250回つばさキャット100回ぐらいやった

最後の方はなでこスネイク画面をみないでも打てるなった

 

 

好きじゃないと周回できないよ

つばさキャットの曲をここまで聞かされるとは思わなかった

せめて、メダルブースターのイベントがほしかった

幽遊白書のコラボは敵が強すぎという酷いパターンがあったが

 これほど時間がかかるコラボはなかったと思う

 

ちなみにgamewithナウシカさんはお金で解決していた。羨ましい

 10連ガチャで15,000コインが手に入る

それを120連していた。すげー

 

firebase functionsでサムネイル画像作成

masalib.hatenablog.com

前回でファイルアップができるようになった
その画像をもとに色々できるようなのでまずはサムネイル画像作成をやってみました

やりたい事

firebaseのstorageにファイルがアップされたら
changeイベントを取得してfirebaseのfunctionsを起動して
サムネイル画像を作成する

パッケージの設定

npmのパッケージの設定

/functions/package.json

{
  "name": "functions",
  "description": "Cloud Functions for Firebase",
  "dependencies": {
    "firebase-admin": "^4.2.1",
    "firebase-functions": "^0.5.7",
    "request": "^2.81.0",
    "lodash": "^4.17.4",
    "request-promise": "^4.2.1",
    "@google-cloud/storage": "^0.4.0",
    "child-process-promise": "^2.2.0",
    "mkdirp": "^0.5.1",
    "mkdirp-promise": "^4.0.0"
  },
  "private": true
}

記載が完了したら

npm installのコマンドでインストールする

/functions/index.js

const mkdirp = require('mkdirp-promise');
// Include a Service Account Key to use a Signed URL
//const gcs = require('@google-cloud/storage')({keyFilename: 'service-account-credentials.json'});
var gcs = require('@google-cloud/storage')({
  projectId: 'angular-study-chat',
  keyFilename: './service-account-credentials.json'
});

const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

// Max height and width of the thumbnail in pixels.
const THUMB_MAX_HEIGHT = 200;
const THUMB_MAX_WIDTH = 200;
// Thumbnail prefix added to file names.
const THUMB_PREFIX = 'thumb_';
//thumbnail

exports.generateThumbnail = functions.storage.object().onChange(event => {
  // File and directory paths.
  const filePath = event.data.name;
  const fileDir = path.dirname(filePath);
  const fileName = path.basename(filePath);
  const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`));
  const tempLocalFile = path.join(os.tmpdir(), filePath);
  const tempLocalDir = path.dirname(tempLocalFile);
  const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);

//  console.log('filePath');
//  console.log(filePath);

  // Exit if this is triggered on a file that is not an image.
  if (!event.data.contentType.startsWith('image/')) {
    console.log('This is not an image.');
    return;
  }

  // Exit if the image is already a thumbnail.
  if (fileName.startsWith(THUMB_PREFIX)) {
    console.log('Already a Thumbnail.');
    return;
  }

  // Exit if this is a move or deletion event.
  if (event.data.resourceState === 'not_exists') {
    console.log('This is a deletion event.');
    return;
  }

  // Cloud Storage files.
  const bucket = gcs.bucket(event.data.bucket);
  const file = bucket.file(filePath);
  const thumbFile = bucket.file(thumbFilePath);

  // Create the temp directory where the storage file will be downloaded.
  return mkdirp(tempLocalDir).then(() => {
    // Download file from bucket.
    return file.download({destination: tempLocalFile});
  }).then(() => {
    console.log('The file has been downloaded to', tempLocalFile);
    // Generate a thumbnail using ImageMagick.
    return spawn('convert', [tempLocalFile, '-thumbnail', `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile]);
  }).then(() => {
    console.log('Thumbnail created at', tempLocalThumbFile);
    // Uploading the Thumbnail.
    return bucket.upload(tempLocalThumbFile, {destination: thumbFilePath});
  }).then(() => {
    console.log('Thumbnail uploaded to Storage at', thumbFilePath);
    // Once the image has been uploaded delete the local files to free up disk space.
    fs.unlinkSync(tempLocalFile);
    fs.unlinkSync(tempLocalThumbFile);
    // Get the Signed URLs for the thumbnail and original image.
    const config = {
      action: 'read',
      expires: '03-01-2500'
    };
    return Promise.all([
      thumbFile.getSignedUrl(config),
      file.getSignedUrl(config)
    ]);
  }).then(results => {
    console.log('Got Signed URLs.');
    const thumbResult = results[0];
    const originalResult = results[1];
    const thumbFileUrl = thumbResult[0];
    const fileUrl = originalResult[0];
    // Add the URLs to the Database
    return admin.database().ref('images').push({path: fileUrl, thumbnail: thumbFileUrl});
  }).then(() => console.log('Thumbnail URLs saved to database.'));
});

記載が終わったら
firebase deploy --only functions
でデプロイするが

Error: ENOENT: no such file or directory, open 'service-account-credentials.json'
    at Error (native)

あれ・・・
サンプルに書いてありました

f:id:masalib:20170903205336j:plain

なのでservice-account-credentials.jsonをつくることにしました
firebaseのコンソール画面で

f:id:masalib:20170903214421j:plain

①歯車のマークをクリックする
②ユーザーと権限をクリックする

f:id:masalib:20170903214451j:plain

①サービスアカウント
②サービスアカウントを作成をクリックする

f:id:masalib:20170903214506j:plain

①サービスアカウント名を適当にいれる
②新しい秘密鍵の提供をクリック
JSONをクリックする
④G Suiteドメイン全体の委任を有効にするをクリック
⑤役割を選択する
⑥ストレージのストレージ管理者

この作成したjsonファイルをservice-account-credentials.jsonにリネームして
/functions/の配下においてもう1度デプロイする
firebase deploy --only functions

画面

f:id:masalib:20170903220107j:plain
f:id:masalib:20170903221028j:plain

ちなみにサービスアカウントをミスをすると以下のエラーがでた

ApiError: Forbidden
    at new util.ApiError (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:107:10)
    at Object.parseHttpRespMessage (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:149:33)
    at Object.handleResp (/user_code/node_modules/@google-cloud/storage/node_modules/@google-cloud/common/src/util.js:124:18)
    at Duplexify.<anonymous> (/user_code/node_modules/@google-cloud/storage/src/file.js:711:21)
    at emitOne (events.js:96:13)
    at Duplexify.emit (events.js:188:7)
    at emitOne (events.js:96:13)
    at DestroyableTransform.emit (events.js:188:7)
    at emitOne (events.js:96:13)
    at Request.emit (events.js:188:7)
    at Request.<anonymous> (/user_code/node_modules/@google-cloud/storage/node_modules/request/request.js:1108:14)
    at emitOne (events.js:101:20)
    at Request.emit (events.js:188:7)
    at IncomingMessage.<anonymous> (/user_code/node_modules/@google-cloud/storage/node_modules/request/request.js:1091:12)
    at IncomingMessage.g (events.js:292:16)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:80:11)
    at process._tickDomainCallback (internal/process/next_tick.js:128:9)

https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1388
このエラーがでたらサービスアカウントにミスがあります

Angular2/4 firebaseのストレージにアップ

今回も
https://github.com/codediodeio/angular-firestarter/tree/master/src/app/uploads
を参考にしています

サンプルとして既にあるのですが
ファイルアップベースにfirebase functionを動かしたりしたいので
1から作って理解したいと思いやっています

続きを読む