onix-gen-funstory
Version:
onix generator
397 lines (365 loc) • 14.6 kB
text/typescript
import { promises as fs } from 'fs';
import * as path from 'path';
import * as xml2js from 'xml2js';
import moment from 'moment';
const readFile = fs.readFile;
// const writeFile = fs.writeFile;
// const readdir = fs.readdir;
// const copyFile = fs.copyFile;
// const mkdir = fs.mkdir;
export declare type TCurrencyCode = 'USD' | 'CAD' | 'GBP';
export declare type TCountriesIncluded = 'CA' | 'GB' | 'AT' | 'BE' | 'CY' | 'DE' | 'EE' | 'ES' | 'FI' | 'FR' | 'GR' | 'IE' | 'IT' | 'LT' | 'LU' | 'LV' | 'MT' | 'NL' | 'PT' | 'SI' | 'SK';
export declare type TTranslator = 'Babel Novel' | 'Lemon Novel' | 'Fancy Novel';
export declare interface IBookPrice {
currencyCode: TCurrencyCode;
priceAmount: number;
countriesIncluded: TCountriesIncluded[] | ['WORLD'];
}
export declare interface IBookOnixInfo {
bookName: string;
description: string;
author: string;
volume: number;
translator: TTranslator;
isbn: string;
subjectCode: string;
price: IBookPrice[];
keywords: string[];
subTitle?: string;
publicationDate?: string;
preOrderDate?: string;
salesRestriction?: 'ALL' | 'TOP_FIVE' | 'KINDLE_ONLY';
pageCount?: number;
takedown?: boolean;
}
export declare interface IBookChapter {
title: string;
content: string[];
}
export declare interface IinitOption {
senderName: string;
contactName: string;
emailAddress: string;
cityOfPublication: string;
countryOfManufacture: TCountriesIncluded | 'CN';
publisherName: string;
websiteLink: string;
}
export const xml2jsParser = async (text: string): Promise<any> => {
const parser = new xml2js.Parser();
return new Promise((resolve, reject) => {
parser.parseString(text, (err: any, result: any) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
export class ONIXGenerator {
private initOption: IinitOption = {
senderName: 'Funstory',
contactName: 'Funstory',
emailAddress: 'email@email.com',
cityOfPublication: 'BeiJing',
countryOfManufacture: 'CN',
publisherName: 'Funstory',
websiteLink: 'https://funstory.ai',
};
private tempObj: any;
constructor(initOption: IinitOption) {
if (initOption) {
this.initOption = initOption;
}
this.tempObj = '';
}
public async init(initOption?: IinitOption) {
if (initOption) {
this.initOption = initOption;
}
// 读取ONIX模板xml
const onixTmp = await readFile(path.join(__dirname, `./onixTmp.xml`));
// ONIX模板xml2js
this.tempObj = await xml2jsParser(onixTmp.toString('utf8'));
}
public getTemp() {
return this.tempObj;
}
public genONIX(bookinfo: IBookOnixInfo): string {
if (this.tempObj === '') {
throw new Error('please run init() first');
}
const onixObj = {...this.tempObj};
onixObj.ONIXMessage.Header[0].Sender[0].SenderName = this.initOption.senderName;
onixObj.ONIXMessage.Header[0].Sender[0].ContactName = this.initOption.contactName;
onixObj.ONIXMessage.Header[0].Sender[0].EmailAddress = this.initOption.emailAddress;
// onixObj.ONIXMessage.Product[0].DescriptiveDetail[0]
// .CountryOfManufacture = this.initOption.countryOfManufacture;
onixObj.ONIXMessage.Product[0].PublishingDetail[0]
.Publisher[0].PublisherName = this.initOption.publisherName;
onixObj.ONIXMessage.Product[0].PublishingDetail[0]
.Publisher[0].Website[0].WebsiteLink = this.initOption.websiteLink;
onixObj.ONIXMessage.Product[0].PublishingDetail[0]
.CityOfPublication = this.initOption.cityOfPublication;
onixObj.ONIXMessage.Product[0].PublishingDetail[0]
.CountryOfPublication = this.initOption.countryOfManufacture;
onixObj.ONIXMessage.Product[0].ProductSupply[0]
.SupplyDetail[0].Supplier[0].SupplierName = this.initOption.publisherName;
// ISBN
const isbnNum = bookinfo.isbn;
onixObj.ONIXMessage.Product[0].RecordReference = isbnNum;
onixObj.ONIXMessage.Product[0].ProductIdentifier[0].IDValue = isbnNum;
// 书名
const bookTitle = bookinfo.bookName;
const volumeNum = bookinfo.volume;
const subTitle = bookinfo.subTitle;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].TitleDetail[0]
.TitleElement[0].TitleText = `${bookTitle}`;
// 副标题
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].TitleDetail[0]
.TitleElement[0].Subtitle = subTitle ? subTitle : `Book ${volumeNum}`;
// 第几卷(系列号)
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Collection[0]
.CollectionSequence[0].CollectionSequenceNumber = volumeNum;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Collection[0]
.TitleDetail[0].TitleElement[0].TitleText = `Book ${volumeNum}`;
// 作者
const bookAuthor = bookinfo.author.split(' ');
const familyName1 = bookAuthor.shift() || '';
const familyName = familyName1[0] ? `${familyName1[0].toUpperCase()}${familyName1.slice(1)}` : '';
const authorName1 = bookAuthor.join('');
const authorName = authorName1[0] ? `${authorName1[0].toUpperCase()}${authorName1.slice(1)}` : '';
// onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[0].KeyNames = bookAuthor;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[0].PersonName = `${familyName} ${authorName}`;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[0].PersonNameInverted = `${authorName}, ${familyName}`;
// 译者
const bookTranslator = bookinfo.translator.split(' ');
if (bookTranslator.length > 0) {
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[1].PersonName = `${bookTranslator[0]} ${bookTranslator[1]}`;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Contributor[1].PersonNameInverted = `${bookTranslator[1]}, ${bookTranslator[0]}`;
}
const bookPageCount = bookinfo.pageCount;
if (bookPageCount) {
// onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent = [{}];
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent[0].ExtentType = '00';
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent[0].ExtentValue = bookPageCount;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent[0].ExtentUnit = '03';
} else {
delete onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Extent;
}
// 小说类型 详见https://bisg.org/page/Fiction ['FIC008000', 'FIC009000', 'FIC028000']
const aBISACEdition = bookinfo.subjectCode;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Subject[0].SubjectCode = aBISACEdition;
// 关键词
const bookKeywords = bookinfo.keywords;
if (bookKeywords.length > 0) {
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Subject[1] = {};
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0].Subject[1].SubjectSchemeIdentifier = 20;
onixObj.ONIXMessage.Product[0].DescriptiveDetail[0]
.Subject[1].SubjectHeadingText = bookKeywords.join('; ');
}
// 小说简介
const description = bookinfo.description.replace(/(\r|\n)+/g, '').trim();
onixObj.ONIXMessage.Product[0].CollateralDetail[0].TextContent[0].Text[0]._ = description;
const nowdate = moment();
const publicationDate = bookinfo.publicationDate ? moment(bookinfo.publicationDate) : nowdate;
const preOrderDate = bookinfo.preOrderDate ? moment(bookinfo.preOrderDate) : undefined;
const publicationDateTime = parseInt(publicationDate.format('x'), 10);
const nowDateTime = parseInt(nowdate.format('x'), 10);
// 是否未发布 根据发布日期是否大于当前日期对比
const noPublushed: boolean = publicationDateTime > nowDateTime;
// 发送日期
onixObj.ONIXMessage.Header[0].SentDateTime = nowdate.format('YYYYMMDDTHHmm');
// 出版日期
onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingDate[0] = {
PublishingDateRole: ['01'],
Date: [{
$: { dateformat: '00' },
_: publicationDate.format('YYYYMMDD'),
}],
};
// 解禁日期
onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingDate[1] = {
PublishingDateRole: ['02'],
Date: [{
$: { dateformat: '00' },
_: publicationDate.format('YYYYMMDD'),
}],
};
// 上市日期
onixObj.ONIXMessage.Product[0].ProductSupply[0].
MarketPublishingDetail[0].MarketDate[0].Date[0]._ = publicationDate.format('YYYYMMDD');
// 是否可用 10 Not yet available, 20 Available
onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0]
.ProductAvailability[0] = noPublushed ? '10' : '20';
// 出版状态 04 Active, 02 Forthcoming
onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingStatus[0] = noPublushed ? '02' : '04';
onixObj.ONIXMessage.Product[0].ProductSupply[0].MarketPublishingDetail[0].MarketPublishingStatus[0] = noPublushed ? '02' : '04';
// 预售信息
if (preOrderDate && (parseInt(preOrderDate.format('x'), 10) < publicationDateTime)) {
// 预售日期
onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingDate[2] = {
PublishingDateRole: ['09'],
Date: [{
$: { dateformat: '00' },
_: preOrderDate.format('YYYYMMDD'),
}],
};
}
// if (noPublushed) {
// onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0].SupplyDate = [];
// onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0].SupplyDate[0] = {
// SupplyDateRole: '02',
// Date: [{
// $: { dateformat: '00' },
// _: publicationDate.format('YYYYMMDD'),
// }],
// };
// onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0].SupplyDate[1] = {
// SupplyDateRole: '08',
// Date: [{
// $: { dateformat: '00' },
// _: publicationDate.format('YYYYMMDD'),
// }],
// };
// }
const salesRestriction = bookinfo.salesRestriction || 'KINDLE_ONLY';
switch (salesRestriction) {
case 'KINDLE_ONLY':
onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction = [];
onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction[0] = {
SalesRestrictionType: ['04'],
SalesOutlet: [
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['AMZ']
}],
SalesOutletName: ['Amazon eBookBase']
},
],
};
break;
case 'TOP_FIVE':
onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction = [];
onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction[0] = {
SalesRestrictionType: ['04'],
SalesOutlet: [
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['AMZ']
}],
SalesOutletName: ['Amazon eBookBase']
},
// {
// SalesOutletIdentifier: [{
// SalesOutletIDType: ['03'],
// IDValue: ['BNO']
// }],
// SalesOutletName: ['Barnes And Noble']
// },
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['GOO']
}],
SalesOutletName: ['Google Books']
},
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['APC']
}],
SalesOutletName: ['iBookstore']
},
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['KBO']
}],
SalesOutletName: ['Kobo']
},
],
};
break;
default:
onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction = [];
onixObj.ONIXMessage.Product[0].PublishingDetail[0].SalesRestriction[0] = {
SalesRestrictionType: ['04'],
SalesOutlet: [
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['AMZ']
}],
SalesOutletName: ['Amazon eBookBase']
},
// {
// SalesOutletIdentifier: [{
// SalesOutletIDType: ['03'],
// IDValue: ['BNO']
// }],
// SalesOutletName: ['Barnes And Noble']
// },
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['GOO']
}],
SalesOutletName: ['Google Books']
},
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['APC']
}],
SalesOutletName: ['iBookstore']
},
{
SalesOutletIdentifier: [{
SalesOutletIDType: ['03'],
IDValue: ['KBO']
}],
SalesOutletName: ['Kobo']
},
],
};
break;
}
// 地区及当地价格
const priceInfo = bookinfo.price;
onixObj.ONIXMessage.Product[0].ProductSupply[0]
.SupplyDetail[0].Price = priceInfo.map((price: any) => ({
PriceType: '01',
PriceStatus: '01',
PriceAmount: price.priceAmount,
CurrencyCode: price.currencyCode,
Territory: [
(price.countriesIncluded.length === 1 && price.countriesIncluded[0] === 'WORLD') ? (
{
RegionsIncluded: price.countriesIncluded[0],
CountriesExcluded: 'CN',
}
) : (
{
CountriesIncluded: price.countriesIncluded.join(' '),
}
)
]
}));
// 返回ONIX xml
// 下架ONIX
if (bookinfo.takedown){
onixObj.ONIXMessage.Product[0].NotificationType[0] = '04';
onixObj.ONIXMessage.Product[0].ProductSupply[0].SupplyDetail[0]
.ProductAvailability[0] = '51';
onixObj.ONIXMessage.Product[0].PublishingDetail[0].PublishingStatus[0] = '07';
onixObj.ONIXMessage.Product[0].ProductSupply[0].MarketPublishingDetail[0]
.MarketPublishingStatus[0] = '07';
}
const js2xmlBuilder2 = new xml2js.Builder({ renderOpts: { pretty: true } });
return js2xmlBuilder2.buildObject(onixObj);
}
}