1#![deny(unsafe_code)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3
4use humantime::format_rfc3339;
5use std::fmt::Display;
6use std::time::SystemTime;
7
8const PREFIX: &str = "og: https://ogp.me/ns#";
9
10#[allow(dead_code)]
11#[derive(Debug)]
12enum OpenGraphDataTypes {
13 Boolean(bool),
14 String(String),
15 Float(f64),
16 Integer(isize),
17 Url(url::Url),
18}
19
20impl Display for OpenGraphDataTypes {
21 fn fmt(&self, f1: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 let str = match self {
23 Self::Boolean(b) => {
24 if *b {
25 "true".to_string()
26 } else {
27 "false".to_string()
28 }
29 }
30 Self::String(s) => s.to_string(),
31 Self::Float(f) => f.to_string(),
32 Self::Integer(i) => i.to_string(),
33 Self::Url(url) => url.to_string(),
34 };
35 write!(f1, "{}", str)
36 }
37}
38
39pub enum Determiner {
41 A,
42 An,
43 The,
44 Blank,
45 Auto,
46}
47
48impl Display for Determiner {
49 fn fmt(&self, f1: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50 let str = match self {
51 Self::A => "a",
52 Self::An => "an",
53 Self::The => "the",
54 Self::Blank => "",
55 Self::Auto => "auto",
56 };
57 write!(f1, "{}", str)
58 }
59}
60
61pub enum PaymentStatus {
63 Pending,
64 Paid,
65 Failed,
66 Expired,
67}
68
69impl Display for PaymentStatus {
70 fn fmt(&self, f1: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
71 let str = match self {
72 Self::Pending => "PENDING",
73 Self::Paid => "PAID",
74 Self::Failed => "FAILED",
75 Self::Expired => "EXPIRED",
76 };
77 write!(f1, "{}", str)
78 }
79}
80
81pub enum Gender {
83 Male,
84 Female,
85}
86
87impl Display for Gender {
88 fn fmt(&self, f1: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 let str = match self {
90 Self::Male => "male",
91 Self::Female => "female",
92 };
93 write!(f1, "{}", str)
94 }
95}
96
97pub trait OpenGraphTypeMarker: Send + Sync + Sized {
98 const TYPE: &'static str;
99 const EXTRA_PREFIX: &'static str;
100
101 fn builder(
102 title: impl Into<&'static str>,
103 image: url::Url,
104 url: url::Url,
105 ) -> OpenGraphBuilder<Self> {
106 OpenGraphBuilder::new(title, image, url)
107 }
108}
109
110#[derive(Debug)]
111pub struct MusicSong;
112
113impl OpenGraphTypeMarker for MusicSong {
114 const TYPE: &'static str = "music.song";
115 const EXTRA_PREFIX: &'static str = "music: https://ogp.me/ns/music#";
116}
117
118#[derive(Debug)]
119pub struct MusicAlbum;
120
121impl OpenGraphTypeMarker for MusicAlbum {
122 const TYPE: &'static str = "music.album";
123 const EXTRA_PREFIX: &'static str = "music: https://ogp.me/ns/music#";
124}
125
126#[derive(Debug)]
127pub struct MusicPlaylist;
128
129impl OpenGraphTypeMarker for MusicPlaylist {
130 const TYPE: &'static str = "music.playlist";
131 const EXTRA_PREFIX: &'static str = "music: https://ogp.me/ns/music#";
132}
133
134#[derive(Debug)]
135pub struct MusicRadioStation;
136
137impl OpenGraphTypeMarker for MusicRadioStation {
138 const TYPE: &'static str = "music.radio_station";
139 const EXTRA_PREFIX: &'static str = "music: https://ogp.me/ns/music#";
140}
141
142#[derive(Debug)]
143pub struct VideoMovie;
144
145impl OpenGraphTypeMarker for VideoMovie {
146 const TYPE: &'static str = "video.movie";
147 const EXTRA_PREFIX: &'static str = "video: https://ogp.me/ns/video#";
148}
149
150#[derive(Debug)]
151pub struct VideoEpisode;
152
153impl OpenGraphTypeMarker for VideoEpisode {
154 const TYPE: &'static str = "video.episode";
155 const EXTRA_PREFIX: &'static str = "video: https://ogp.me/ns/video#";
156}
157
158#[derive(Debug)]
159pub struct VideoTvShow;
160
161impl OpenGraphTypeMarker for VideoTvShow {
162 const TYPE: &'static str = "video.tv_show";
163 const EXTRA_PREFIX: &'static str = "video: https://ogp.me/ns/video#";
164}
165
166#[derive(Debug)]
167pub struct VideoOther;
168
169impl OpenGraphTypeMarker for VideoOther {
170 const TYPE: &'static str = "video.other";
171 const EXTRA_PREFIX: &'static str = "video: https://ogp.me/ns/video#";
172}
173
174#[derive(Debug)]
175pub struct Article;
176
177impl OpenGraphTypeMarker for Article {
178 const TYPE: &'static str = "article";
179 const EXTRA_PREFIX: &'static str = "article: https://ogp.me/ns/article#";
180}
181
182#[derive(Debug)]
183pub struct Book;
184
185impl OpenGraphTypeMarker for Book {
186 const TYPE: &'static str = "book";
187 const EXTRA_PREFIX: &'static str = "book: https://ogp.me/ns/book#";
188}
189
190#[derive(Debug)]
191pub struct PaymentLink;
192
193impl OpenGraphTypeMarker for PaymentLink {
194 const TYPE: &'static str = "payment.link";
195 const EXTRA_PREFIX: &'static str = "payment: https://ogp.me/ns/payment#";
196}
197
198#[derive(Debug)]
199pub struct Profile;
200
201impl OpenGraphTypeMarker for Profile {
202 const TYPE: &'static str = "profile";
203 const EXTRA_PREFIX: &'static str = "profile: https://ogp.me/ns/profile#";
204}
205
206#[derive(Debug)]
207pub struct Website;
208
209impl OpenGraphTypeMarker for Website {
210 const TYPE: &'static str = "website";
211 const EXTRA_PREFIX: &'static str = "website: https://ogp.me/ns/website#";
212}
213
214#[derive(Debug)]
215pub struct OpenGraphBuilder<M: OpenGraphTypeMarker> {
216 list: Vec<(&'static str, OpenGraphDataTypes)>,
217 marker: std::marker::PhantomData<M>,
218}
219
220impl<M: OpenGraphTypeMarker> OpenGraphBuilder<M> {
221 pub fn new(title: impl Into<&'static str>, image: url::Url, url: url::Url) -> Self {
222 Self {
223 list: vec![
224 (
225 "og:title",
226 OpenGraphDataTypes::String(title.into().to_string()),
227 ),
228 ("og:image", OpenGraphDataTypes::Url(image)),
229 ("og:url", OpenGraphDataTypes::Url(url)),
230 ],
231 marker: std::marker::PhantomData,
232 }
233 }
234
235 pub fn image_secure_url(mut self, image_secure_url: url::Url) -> Self {
236 self.list.push((
237 "og:image:secure_url",
238 OpenGraphDataTypes::Url(image_secure_url),
239 ));
240 self
241 }
242
243 pub fn image_type(mut self, image_type: impl Into<&'static str>) -> Self {
244 self.list.push((
245 "og:image:type",
246 OpenGraphDataTypes::String(image_type.into().to_string()),
247 ));
248 self
249 }
250
251 pub fn image_width(mut self, image_width: isize) -> Self {
252 self.list
253 .push(("og:image:width", OpenGraphDataTypes::Integer(image_width)));
254 self
255 }
256
257 pub fn image_height(mut self, image_height: isize) -> Self {
258 self.list
259 .push(("og:image:height", OpenGraphDataTypes::Integer(image_height)));
260 self
261 }
262
263 pub fn image_alt(mut self, image_alt: impl Into<&'static str>) -> Self {
264 self.list.push((
265 "og:image:alt",
266 OpenGraphDataTypes::String(image_alt.into().to_string()),
267 ));
268 self
269 }
270
271 pub fn audio(mut self, audio: url::Url) -> Self {
272 self.list.push(("og:audio", OpenGraphDataTypes::Url(audio)));
273 self
274 }
275
276 pub fn audio_secure_url(mut self, audio_secure_url: url::Url) -> Self {
277 self.list.push((
278 "og:audio:secure_url",
279 OpenGraphDataTypes::Url(audio_secure_url),
280 ));
281 self
282 }
283
284 pub fn audio_type(mut self, audio_type: impl Into<&'static str>) -> Self {
285 self.list.push((
286 "og:audio:type",
287 OpenGraphDataTypes::String(audio_type.into().to_string()),
288 ));
289 self
290 }
291
292 pub fn description(mut self, description: impl Into<&'static str>) -> Self {
293 self.list.push((
294 "og:description",
295 OpenGraphDataTypes::String(description.into().to_string()),
296 ));
297 self
298 }
299
300 pub fn determiner(mut self, determiner: Determiner) -> Self {
301 self.list.push((
302 "og:determiner",
303 OpenGraphDataTypes::String(determiner.to_string()),
304 ));
305 self
306 }
307
308 pub fn locale(mut self, locale: impl Into<&'static str>) -> Self {
309 self.list.push((
310 "og:locale",
311 OpenGraphDataTypes::String(locale.into().to_string()),
312 ));
313 self
314 }
315
316 pub fn locale_alternate(mut self, locales: Vec<impl Into<&'static str>>) -> Self {
317 for locale in locales {
318 self.list.push((
319 "og:locale:alternate",
320 OpenGraphDataTypes::String(locale.into().to_string()),
321 ));
322 }
323 self
324 }
325
326 pub fn site_name(mut self, site_name: impl Into<&'static str>) -> Self {
327 self.list.push((
328 "og:site_name",
329 OpenGraphDataTypes::String(site_name.into().to_string()),
330 ));
331 self
332 }
333
334 pub fn video(mut self, video: url::Url) -> Self {
335 self.list.push(("og:video", OpenGraphDataTypes::Url(video)));
336 self
337 }
338
339 pub fn video_secure_url(mut self, video_secure_url: url::Url) -> Self {
340 self.list.push((
341 "og:video:secure_url",
342 OpenGraphDataTypes::Url(video_secure_url),
343 ));
344 self
345 }
346
347 pub fn video_type(mut self, video_type: impl Into<&'static str>) -> Self {
348 self.list.push((
349 "og:video:type",
350 OpenGraphDataTypes::String(video_type.into().to_string()),
351 ));
352 self
353 }
354
355 pub fn video_width(mut self, video_width: isize) -> Self {
356 self.list
357 .push(("og:video:width", OpenGraphDataTypes::Integer(video_width)));
358 self
359 }
360
361 pub fn video_height(mut self, video_height: isize) -> Self {
362 self.list
363 .push(("og:video:height", OpenGraphDataTypes::Integer(video_height)));
364 self
365 }
366
367 pub fn video_alt(mut self, video_tag: impl Into<&'static str>) -> Self {
368 self.list.push((
369 "og:video:alt",
370 OpenGraphDataTypes::String(video_tag.into().to_string()),
371 ));
372 self
373 }
374
375 pub fn custom(mut self, key: impl Into<&'static str>, value: impl Into<&'static str>) -> Self {
376 self.list.push((
377 key.into(),
378 OpenGraphDataTypes::String(value.into().to_string()),
379 ));
380 self
381 }
382
383 pub fn build(self) -> OpenGraph {
384 OpenGraph {
385 prefix: format!("{} {}", PREFIX, M::EXTRA_PREFIX),
386 og_type: M::TYPE.to_string(),
387 list: self
388 .list
389 .iter()
390 .map(|i| (i.0.to_string(), i.1.to_string()))
391 .collect(),
392 }
393 }
394}
395
396impl<M: OpenGraphTypeMarker> Into<OpenGraph> for OpenGraphBuilder<M> {
397 fn into(self) -> OpenGraph {
398 self.build()
399 }
400}
401
402impl OpenGraphBuilder<MusicSong> {
403 pub fn music_duration(mut self, music_duration: isize) -> Self {
404 if music_duration >= 1 {
405 self.list.push((
406 "music:duration",
407 OpenGraphDataTypes::Integer(music_duration),
408 ));
409 }
410 self
411 }
412
413 pub fn music_album(mut self, music_album: url::Url) -> Self {
414 self.list
415 .push(("music:album", OpenGraphDataTypes::Url(music_album)));
416 self
417 }
418
419 pub fn music_album_disc(mut self, music_album_disc: isize) -> Self {
420 if music_album_disc >= 1 {
421 self.list.push((
422 "music:album:disc",
423 OpenGraphDataTypes::Integer(music_album_disc),
424 ));
425 }
426 self
427 }
428
429 pub fn music_album_track(mut self, music_album_track: isize) -> Self {
430 if music_album_track >= 1 {
431 self.list.push((
432 "music:album:track",
433 OpenGraphDataTypes::Integer(music_album_track),
434 ));
435 }
436 self
437 }
438
439 pub fn music_musician(mut self, music_musician: url::Url) -> Self {
440 self.list
441 .push(("music:musician", OpenGraphDataTypes::Url(music_musician)));
442 self
443 }
444}
445
446impl OpenGraphBuilder<MusicAlbum> {
447 pub fn music_song(mut self, music_song: url::Url) -> Self {
448 self.list
449 .push(("music:song", OpenGraphDataTypes::Url(music_song)));
450 self
451 }
452
453 pub fn music_song_disc(mut self, music_song_disc: isize) -> Self {
454 if music_song_disc >= 1 {
455 self.list.push((
456 "music:song:disc",
457 OpenGraphDataTypes::Integer(music_song_disc),
458 ));
459 }
460 self
461 }
462
463 pub fn music_song_track(mut self, music_song_track: isize) -> Self {
464 if music_song_track >= 1 {
465 self.list.push((
466 "music:song:track",
467 OpenGraphDataTypes::Integer(music_song_track),
468 ));
469 }
470 self
471 }
472
473 pub fn music_musician(mut self, music_musician: url::Url) -> Self {
474 self.list
475 .push(("music:musician", OpenGraphDataTypes::Url(music_musician)));
476 self
477 }
478
479 pub fn music_release_date(mut self, music_release_date: SystemTime) -> Self {
480 self.list.push((
481 "music:release_date",
482 OpenGraphDataTypes::String(format_rfc3339(music_release_date).to_string()),
483 ));
484 self
485 }
486
487 #[cfg(feature = "chrono")]
488 pub fn music_release_date_chrono(
489 mut self,
490 music_release_date: impl Into<chrono::DateTime<chrono::Utc>>,
491 ) -> Self {
492 self.list.push((
493 "music:release_date",
494 OpenGraphDataTypes::String(music_release_date.into().to_rfc3339()),
495 ));
496 self
497 }
498}
499
500impl OpenGraphBuilder<MusicPlaylist> {
501 pub fn music_song(mut self, music_song: url::Url) -> Self {
502 self.list
503 .push(("music:song", OpenGraphDataTypes::Url(music_song)));
504 self
505 }
506
507 pub fn music_song_disc(mut self, music_song_disc: isize) -> Self {
508 if music_song_disc >= 1 {
509 self.list.push((
510 "music:song:disc",
511 OpenGraphDataTypes::Integer(music_song_disc),
512 ));
513 }
514 self
515 }
516
517 pub fn music_song_track(mut self, music_song_track: isize) -> Self {
518 if music_song_track >= 1 {
519 self.list.push((
520 "music:song:track",
521 OpenGraphDataTypes::Integer(music_song_track),
522 ));
523 }
524 self
525 }
526
527 pub fn music_creator(mut self, music_creator: url::Url) -> Self {
528 self.list
529 .push(("music:creator", OpenGraphDataTypes::Url(music_creator)));
530 self
531 }
532}
533
534impl OpenGraphBuilder<MusicRadioStation> {
535 pub fn music_creator(mut self, music_creator: url::Url) -> Self {
536 self.list
537 .push(("music:creator", OpenGraphDataTypes::Url(music_creator)));
538 self
539 }
540}
541
542impl OpenGraphBuilder<VideoMovie> {
543 pub fn video_actor(mut self, video_actor: url::Url) -> Self {
544 self.list
545 .push(("video:actor", OpenGraphDataTypes::Url(video_actor)));
546 self
547 }
548
549 pub fn video_actor_role(mut self, video_actor_role: impl Into<&'static str>) -> Self {
550 self.list.push((
551 "video:actor:role",
552 OpenGraphDataTypes::String(video_actor_role.into().to_string()),
553 ));
554 self
555 }
556
557 pub fn video_director(mut self, video_director: url::Url) -> Self {
558 self.list
559 .push(("video:director", OpenGraphDataTypes::Url(video_director)));
560 self
561 }
562
563 pub fn video_writer(mut self, video_writer: url::Url) -> Self {
564 self.list
565 .push(("video:writer", OpenGraphDataTypes::Url(video_writer)));
566 self
567 }
568
569 pub fn video_duration(mut self, video_duration: isize) -> Self {
570 if video_duration >= 1 {
571 self.list.push((
572 "video:duration",
573 OpenGraphDataTypes::Integer(video_duration),
574 ));
575 }
576 self
577 }
578
579 pub fn video_release_date(mut self, video_release_date: SystemTime) -> Self {
580 self.list.push((
581 "video:release_date",
582 OpenGraphDataTypes::String(format_rfc3339(video_release_date).to_string()),
583 ));
584 self
585 }
586
587 #[cfg(feature = "chrono")]
588 pub fn video_release_date_chrono(
589 mut self,
590 video_release_date: impl Into<chrono::DateTime<chrono::Utc>>,
591 ) -> Self {
592 self.list.push((
593 "video:release_date",
594 OpenGraphDataTypes::String(video_release_date.into().to_rfc3339()),
595 ));
596 self
597 }
598
599 pub fn video_tag(mut self, video_tag: impl Into<&'static str>) -> Self {
600 self.list.push((
601 "video:tag",
602 OpenGraphDataTypes::String(video_tag.into().to_string()),
603 ));
604 self
605 }
606}
607
608impl OpenGraphBuilder<VideoEpisode> {
609 pub fn video_actor(mut self, video_actor: url::Url) -> Self {
610 self.list
611 .push(("video:actor", OpenGraphDataTypes::Url(video_actor)));
612 self
613 }
614
615 pub fn video_actor_role(mut self, video_actor_role: impl Into<&'static str>) -> Self {
616 self.list.push((
617 "video:actor:role",
618 OpenGraphDataTypes::String(video_actor_role.into().to_string()),
619 ));
620 self
621 }
622
623 pub fn video_director(mut self, video_director: url::Url) -> Self {
624 self.list
625 .push(("video:director", OpenGraphDataTypes::Url(video_director)));
626 self
627 }
628
629 pub fn video_writer(mut self, video_writer: url::Url) -> Self {
630 self.list
631 .push(("video:writer", OpenGraphDataTypes::Url(video_writer)));
632 self
633 }
634
635 pub fn video_duration(mut self, video_duration: isize) -> Self {
636 if video_duration >= 1 {
637 self.list.push((
638 "video:duration",
639 OpenGraphDataTypes::Integer(video_duration),
640 ));
641 }
642 self
643 }
644
645 pub fn video_release_date(mut self, video_release_date: SystemTime) -> Self {
646 self.list.push((
647 "video:release_date",
648 OpenGraphDataTypes::String(format_rfc3339(video_release_date).to_string()),
649 ));
650 self
651 }
652
653 #[cfg(feature = "chrono")]
654 pub fn video_release_date_chrono(
655 mut self,
656 video_release_date: impl Into<chrono::DateTime<chrono::Utc>>,
657 ) -> Self {
658 self.list.push((
659 "video:release_date",
660 OpenGraphDataTypes::String(video_release_date.into().to_rfc3339()),
661 ));
662 self
663 }
664
665 pub fn video_tag(mut self, video_tag: impl Into<&'static str>) -> Self {
666 self.list.push((
667 "video:tag",
668 OpenGraphDataTypes::String(video_tag.into().to_string()),
669 ));
670 self
671 }
672
673 pub fn video_series(mut self, video_series: url::Url) -> Self {
674 self.list
675 .push(("video:series", OpenGraphDataTypes::Url(video_series)));
676 self
677 }
678}
679
680impl OpenGraphBuilder<VideoTvShow> {
681 pub fn video_actor(mut self, video_actor: url::Url) -> Self {
682 self.list
683 .push(("video:actor", OpenGraphDataTypes::Url(video_actor)));
684 self
685 }
686
687 pub fn video_actor_role(mut self, video_actor_role: impl Into<&'static str>) -> Self {
688 self.list.push((
689 "video:actor:role",
690 OpenGraphDataTypes::String(video_actor_role.into().to_string()),
691 ));
692 self
693 }
694
695 pub fn video_director(mut self, video_director: url::Url) -> Self {
696 self.list
697 .push(("video:director", OpenGraphDataTypes::Url(video_director)));
698 self
699 }
700
701 pub fn video_writer(mut self, video_writer: url::Url) -> Self {
702 self.list
703 .push(("video:writer", OpenGraphDataTypes::Url(video_writer)));
704 self
705 }
706
707 pub fn video_duration(mut self, video_duration: isize) -> Self {
708 if video_duration >= 1 {
709 self.list.push((
710 "video:duration",
711 OpenGraphDataTypes::Integer(video_duration),
712 ));
713 }
714 self
715 }
716
717 #[cfg(feature = "chrono")]
718 pub fn video_release_date_chrono(
719 mut self,
720 video_release_date: impl Into<chrono::DateTime<chrono::Utc>>,
721 ) -> Self {
722 self.list.push((
723 "video:release_date",
724 OpenGraphDataTypes::String(video_release_date.into().to_rfc3339()),
725 ));
726 self
727 }
728
729 pub fn video_tag(mut self, video_tag: impl Into<&'static str>) -> Self {
730 self.list.push((
731 "video:tag",
732 OpenGraphDataTypes::String(video_tag.into().to_string()),
733 ));
734 self
735 }
736}
737
738impl OpenGraphBuilder<VideoOther> {
739 pub fn video_actor(mut self, video_actor: url::Url) -> Self {
740 self.list
741 .push(("video:actor", OpenGraphDataTypes::Url(video_actor)));
742 self
743 }
744
745 pub fn video_actor_role(mut self, video_actor_role: impl Into<&'static str>) -> Self {
746 self.list.push((
747 "video:actor:role",
748 OpenGraphDataTypes::String(video_actor_role.into().to_string()),
749 ));
750 self
751 }
752
753 pub fn video_director(mut self, video_director: url::Url) -> Self {
754 self.list
755 .push(("video:director", OpenGraphDataTypes::Url(video_director)));
756 self
757 }
758
759 pub fn video_writer(mut self, video_writer: url::Url) -> Self {
760 self.list
761 .push(("video:writer", OpenGraphDataTypes::Url(video_writer)));
762 self
763 }
764
765 pub fn video_duration(mut self, video_duration: isize) -> Self {
766 if video_duration >= 1 {
767 self.list.push((
768 "video:duration",
769 OpenGraphDataTypes::Integer(video_duration),
770 ));
771 }
772 self
773 }
774
775 pub fn video_release_date(mut self, video_release_date: SystemTime) -> Self {
776 self.list.push((
777 "video:release_date",
778 OpenGraphDataTypes::String(format_rfc3339(video_release_date).to_string()),
779 ));
780 self
781 }
782
783 #[cfg(feature = "chrono")]
784 pub fn video_release_date_chrono(
785 mut self,
786 video_release_date: impl Into<chrono::DateTime<chrono::Utc>>,
787 ) -> Self {
788 self.list.push((
789 "video:release_date",
790 OpenGraphDataTypes::String(video_release_date.into().to_rfc3339()),
791 ));
792 self
793 }
794
795 pub fn video_tag(mut self, video_tag: impl Into<&'static str>) -> Self {
796 self.list.push((
797 "video:tag",
798 OpenGraphDataTypes::String(video_tag.into().to_string()),
799 ));
800 self
801 }
802}
803
804impl OpenGraphBuilder<Article> {
805 pub fn article_published_time(mut self, article_published_time: SystemTime) -> Self {
806 self.list.push((
807 "article:published_time",
808 OpenGraphDataTypes::String(format_rfc3339(article_published_time).to_string()),
809 ));
810 self
811 }
812
813 #[cfg(feature = "chrono")]
814 pub fn article_published_time_chrono(
815 mut self,
816 article_published_time: impl Into<chrono::DateTime<chrono::Utc>>,
817 ) -> Self {
818 self.list.push((
819 "article:published_time",
820 OpenGraphDataTypes::String(article_published_time.into().to_rfc3339()),
821 ));
822 self
823 }
824
825 pub fn article_modified_time(mut self, article_modified_time: SystemTime) -> Self {
826 self.list.push((
827 "article:modified_time",
828 OpenGraphDataTypes::String(format_rfc3339(article_modified_time).to_string()),
829 ));
830 self
831 }
832
833 #[cfg(feature = "chrono")]
834 pub fn article_modified_time_chrono(
835 mut self,
836 article_modified_time: impl Into<chrono::DateTime<chrono::Utc>>,
837 ) -> Self {
838 self.list.push((
839 "article:modified_time",
840 OpenGraphDataTypes::String(article_modified_time.into().to_rfc3339()),
841 ));
842 self
843 }
844
845 pub fn article_expiration_time(mut self, article_expiration_time: SystemTime) -> Self {
846 self.list.push((
847 "article:expiration_time",
848 OpenGraphDataTypes::String(format_rfc3339(article_expiration_time).to_string()),
849 ));
850 self
851 }
852
853 #[cfg(feature = "chrono")]
854 pub fn article_expiration_time_chrono(
855 mut self,
856 article_expiration_time: impl Into<chrono::DateTime<chrono::Utc>>,
857 ) -> Self {
858 self.list.push((
859 "article:expiration_time",
860 OpenGraphDataTypes::String(article_expiration_time.into().to_rfc3339()),
861 ));
862 self
863 }
864
865 pub fn article_author(mut self, article_author: url::Url) -> Self {
866 self.list
867 .push(("article:author", OpenGraphDataTypes::Url(article_author)));
868 self
869 }
870
871 pub fn article_section(mut self, article_section: impl Into<&'static str>) -> Self {
872 self.list.push((
873 "article:section",
874 OpenGraphDataTypes::String(article_section.into().to_string()),
875 ));
876 self
877 }
878
879 pub fn article_tag(mut self, article_tag: impl Into<&'static str>) -> Self {
880 self.list.push((
881 "article:tag",
882 OpenGraphDataTypes::String(article_tag.into().to_string()),
883 ));
884 self
885 }
886}
887
888impl OpenGraphBuilder<Book> {
889 pub fn book_author(mut self, book_author: url::Url) -> Self {
890 self.list
891 .push(("book:author", OpenGraphDataTypes::Url(book_author)));
892 self
893 }
894
895 pub fn book_isbn(mut self, book_isbn: impl Into<&'static str>) -> Self {
896 self.list.push((
897 "book:isbn",
898 OpenGraphDataTypes::String(book_isbn.into().to_string()),
899 ));
900 self
901 }
902
903 pub fn book_release_date(mut self, book_release_date: SystemTime) -> Self {
904 self.list.push((
905 "book:release_date",
906 OpenGraphDataTypes::String(format_rfc3339(book_release_date).to_string()),
907 ));
908 self
909 }
910
911 #[cfg(feature = "chrono")]
912 pub fn book_release_data_chrono(
913 mut self,
914 book_release_date: impl Into<chrono::DateTime<chrono::Utc>>,
915 ) -> Self {
916 self.list.push((
917 "book:release_date",
918 OpenGraphDataTypes::String(book_release_date.into().to_rfc3339()),
919 ));
920 self
921 }
922
923 pub fn book_tag(mut self, book_tag: impl Into<&'static str>) -> Self {
924 self.list.push((
925 "book:tag",
926 OpenGraphDataTypes::String(book_tag.into().to_string()),
927 ));
928 self
929 }
930}
931
932impl OpenGraphBuilder<PaymentLink> {
933 pub fn payment_description(mut self, payment_description: impl Into<&'static str>) -> Self {
934 self.list.push((
935 "payment:description",
936 OpenGraphDataTypes::String(payment_description.into().to_string()),
937 ));
938 self
939 }
940
941 pub fn payment_currency(mut self, payment_currency: impl Into<&'static str>) -> Self {
942 self.list.push((
943 "payment:currency",
944 OpenGraphDataTypes::String(payment_currency.into().to_string()),
945 ));
946 self
947 }
948
949 pub fn payment_amount(mut self, payment_amount: impl Into<f64>) -> Self {
950 self.list.push((
951 "payment:amount",
952 OpenGraphDataTypes::Float(payment_amount.into()),
953 ));
954 self
955 }
956
957 #[cfg(feature = "chrono")]
958 pub fn payment_expires_at_chrono(
959 mut self,
960 payment_expires_at: impl Into<chrono::DateTime<chrono::Utc>>,
961 ) -> Self {
962 self.list.push((
963 "payment:expires_at",
964 OpenGraphDataTypes::String(payment_expires_at.into().to_rfc3339()),
965 ));
966 self
967 }
968
969 pub fn payment_status(mut self, payment_status: PaymentStatus) -> Self {
970 self.list.push((
971 "payment:status",
972 OpenGraphDataTypes::String(payment_status.to_string()),
973 ));
974 self
975 }
976
977 pub fn payment_id(mut self, payment_id: impl Into<&'static str>) -> Self {
978 self.list.push((
979 "payment:id",
980 OpenGraphDataTypes::String(payment_id.into().to_string()),
981 ));
982 self
983 }
984
985 pub fn payment_success_url(mut self, payment_success_url: url::Url) -> Self {
986 self.list.push((
987 "payment:success_url",
988 OpenGraphDataTypes::Url(payment_success_url),
989 ));
990 self
991 }
992}
993
994impl OpenGraphBuilder<Profile> {
995 pub fn profile_first_name(mut self, profile_first_name: impl Into<&'static str>) -> Self {
996 self.list.push((
997 "profile:first_name",
998 OpenGraphDataTypes::String(profile_first_name.into().to_string()),
999 ));
1000 self
1001 }
1002
1003 pub fn profile_last_name(mut self, profile_last_name: impl Into<&'static str>) -> Self {
1004 self.list.push((
1005 "profile:last_name",
1006 OpenGraphDataTypes::String(profile_last_name.into().to_string()),
1007 ));
1008 self
1009 }
1010
1011 pub fn profile_username(mut self, profile_username: impl Into<&'static str>) -> Self {
1012 self.list.push((
1013 "profile:username",
1014 OpenGraphDataTypes::String(profile_username.into().to_string()),
1015 ));
1016 self
1017 }
1018
1019 pub fn profile_gender(mut self, profile_gender: Gender) -> Self {
1020 self.list.push((
1021 "profile:gender",
1022 OpenGraphDataTypes::String(profile_gender.to_string()),
1023 ));
1024 self
1025 }
1026}
1027
1028#[derive(Debug, Clone)]
1029pub struct OpenGraph {
1030 pub prefix: String,
1031 pub og_type: String,
1032 pub list: Box<[(String, String)]>,
1033}