← back to Rentv Ad Engine
Full REview reconciliation: producer-page harvest maps 20/22 episodes (16 with official sponsors + real air dates); reconcile-review.py cross-verifies 7 advertisers vs RENTV official record + stamps 15 episode air dates; UI shows REview-verified badge + air dates
c3eae5f2011f45a98a0c3234b4273ead0d0ab945 · 2026-08-07 09:51:18 -0700 · Steve Abrams
Transcript extraction agrees with RENTV official on all 7 recurring sponsors (Rockefeller/Provident exact); ours slightly higher (also catches panels + 4 unparsed episodes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M data/advertisers.jsonM data/manifest.jsonM data/rentvreview.jsonM public/index.htmlM scripts/harvest-rentvreview.pyA scripts/reconcile-review.py
Diff
commit c3eae5f2011f45a98a0c3234b4273ead0d0ab945
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Aug 7 09:51:18 2026 -0700
Full REview reconciliation: producer-page harvest maps 20/22 episodes (16 with official sponsors + real air dates); reconcile-review.py cross-verifies 7 advertisers vs RENTV official record + stamps 15 episode air dates; UI shows REview-verified badge + air dates
Transcript extraction agrees with RENTV official on all 7 recurring sponsors (Rockefeller/Provident exact); ours slightly higher (also catches panels + 4 unparsed episodes).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
data/advertisers.json | 104 ++++++++++++-----
data/manifest.json | 45 ++++---
data/rentvreview.json | 259 ++++++++++++++++++++++++++++++++++-------
public/index.html | 5 +-
scripts/harvest-rentvreview.py | 133 ++++++++++-----------
scripts/reconcile-review.py | 73 ++++++++++++
6 files changed, 456 insertions(+), 163 deletions(-)
diff --git a/data/advertisers.json b/data/advertisers.json
index b73330e..31f6b6b 100644
--- a/data/advertisers.json
+++ b/data/advertisers.json
@@ -121,7 +121,10 @@
"address_status": "found_web",
"addresses": [
"2550 Honolulu Ave, Ste 101, Montrose, CA 91020"
- ]
+ ],
+ "review_verified": true,
+ "review_appearances": 13,
+ "review_official_name": "Commercial Real Estate Inspectors"
},
{
"name": "Fidelity Mortgage Lenders",
@@ -231,7 +234,10 @@
"address_status": "found_web",
"addresses": [
"11952 Wilshire Boulevard, Los Angeles, CA 90025-6608"
- ]
+ ],
+ "review_verified": true,
+ "review_appearances": 13,
+ "review_official_name": "Fidelity Mortgage Lenders"
},
{
"name": "Paramount Property Tax Appeal",
@@ -317,7 +323,10 @@
"address_status": "found_web",
"addresses": [
"14251 Danielson Street, Poway, CA 92064"
- ]
+ ],
+ "review_verified": true,
+ "review_appearances": 9,
+ "review_official_name": "Paramount Property Tax Appeal"
},
{
"name": "Chase Partners",
@@ -390,7 +399,10 @@
"addresses": [
"Chase Partners Ltd., P.O Box 3944, Glendale, CA 91221"
],
- "address_status": "found"
+ "address_status": "found",
+ "review_verified": true,
+ "review_appearances": 7,
+ "review_official_name": "Chase Partners"
},
{
"name": "Redwood Mortgage",
@@ -444,7 +456,10 @@
"addresses": [
"155 Bovet Road, Suite 302 San Mateo, CA 94402"
],
- "address_status": "found"
+ "address_status": "found",
+ "review_verified": true,
+ "review_appearances": 3,
+ "review_official_name": "Redwood Mortgage"
},
{
"name": "Provident Savings Bank",
@@ -484,7 +499,10 @@
"addresses": [
"3756 Central Avenue, Riverside, CA 92506"
],
- "address_status": "found"
+ "address_status": "found",
+ "review_verified": true,
+ "review_appearances": 3,
+ "review_official_name": "Provident Savings Bank"
},
{
"name": "Rockefeller Group",
@@ -518,7 +536,10 @@
"addresses": [
"2325 East Camelback Road, Suite 400, Phoenix, AZ 85016"
],
- "address_status": "found"
+ "address_status": "found",
+ "review_verified": true,
+ "review_appearances": 3,
+ "review_official_name": "Rockefeller Group"
},
{
"name": "The Bascom Group",
@@ -549,7 +570,8 @@
"address_status": "found_web",
"addresses": [
"7 Corporate Park, Suite 100, Irvine, CA 92606"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Advanced Real Estate Services",
@@ -573,7 +595,8 @@
"address_status": "found_web",
"addresses": [
"15320 Barranca Parkway, Suite 150, Irvine, CA 92618"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Advanced Real Estate The Firm",
@@ -597,7 +620,8 @@
"address_status": "found_web",
"addresses": [
"15320 Barranca Parkway, Suite 150, Irvine, CA 92618"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Axo Bank",
@@ -621,7 +645,8 @@
"address_status": "found_web",
"addresses": [
"4350 La Jolla Village Drive, Suite 140, San Diego, CA 92122"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Axos Bank",
@@ -645,7 +670,8 @@
"address_status": "found_web",
"addresses": [
"4350 La Jolla Village Drive, Suite 140, San Diego, CA 92122"
- ]
+ ],
+ "review_verified": false
},
{
"name": "CBRE",
@@ -669,7 +695,8 @@
"address_status": "found_web",
"addresses": [
"400 S Hope Street, 25th Floor, Los Angeles, CA 90071"
- ]
+ ],
+ "review_verified": false
},
{
"name": "CBRE's National Retail Partners West Team",
@@ -695,7 +722,8 @@
"address_status": "found_web",
"addresses": [
"400 S Hope Street, 25th Floor, Los Angeles, CA 90071"
- ]
+ ],
+ "review_verified": false
},
{
"name": "City of Ontario",
@@ -716,7 +744,8 @@
"url": "https://vimeo.com/830276773"
}
],
- "address_status": "needs_web_search"
+ "address_status": "needs_web_search",
+ "review_verified": false
},
{
"name": "First",
@@ -735,7 +764,8 @@
"url": "https://vimeo.com/1039101858"
}
],
- "address_status": "needs_web_search"
+ "address_status": "needs_web_search",
+ "review_verified": false
},
{
"name": "Jones Lang LaSalle (JLL)",
@@ -761,7 +791,8 @@
"address_status": "found_web",
"addresses": [
"515 S Flower Street, Floor 13, Los Angeles, CA 90071"
- ]
+ ],
+ "review_verified": false
},
{
"name": "MG R Real Estate",
@@ -787,7 +818,8 @@
"address_status": "found_web",
"addresses": [
"3800 E Concours St, Suite 350, Ontario, CA 91764"
- ]
+ ],
+ "review_verified": false
},
{
"name": "MGR Real Estate Services",
@@ -813,7 +845,8 @@
"address_status": "found_web",
"addresses": [
"3800 E Concours St, Suite 350, Ontario, CA 91764"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Ms. Rahi TE Bank",
@@ -832,7 +865,8 @@
"url": "https://vimeo.com/862593366"
}
],
- "address_status": "needs_web_search"
+ "address_status": "needs_web_search",
+ "review_verified": false
},
{
"name": "Newmark Merrill Companies",
@@ -860,7 +894,8 @@
"address_status": "found_web",
"addresses": [
"24025 Park Sorrento, Suite 300, Calabasas, CA 91302"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Pacific Southwest Realty Services",
@@ -886,7 +921,8 @@
"address_status": "found_web",
"addresses": [
"7675 Dagget Street, Suite 330, San Diego, CA 92111"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Paragon Commercial Group",
@@ -914,7 +950,8 @@
"address_status": "found_web",
"addresses": [
"133 Penn Street, El Segundo, CA 90245"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Provident Bank",
@@ -938,7 +975,8 @@
"address_status": "found_web",
"addresses": [
"111 Wood Avenue South, Suite 200, Iselin, NJ 08830"
- ]
+ ],
+ "review_verified": false
},
{
"name": "rent TV",
@@ -957,7 +995,8 @@
"url": "https://vimeo.com/721184140"
}
],
- "address_status": "needs_web_search"
+ "address_status": "needs_web_search",
+ "review_verified": false
},
{
"name": "Say What's Properties",
@@ -976,7 +1015,8 @@
"url": "https://vimeo.com/739081927"
}
],
- "address_status": "needs_web_search"
+ "address_status": "needs_web_search",
+ "review_verified": false
},
{
"name": "Torrey Pines Bank",
@@ -1002,7 +1042,8 @@
"address_status": "found_web",
"addresses": [
"12220 El Camino Real, Suite 110, San Diego, CA 92130"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Universe Holdings",
@@ -1026,7 +1067,8 @@
"address_status": "found_web",
"addresses": [
"1875 Century Park E, Suite 1800, Los Angeles, CA 90067"
- ]
+ ],
+ "review_verified": false
},
{
"name": "Walker and Dunlop",
@@ -1050,7 +1092,9 @@
"address_status": "found_web",
"addresses": [
"7272 Wisconsin Avenue, Suite 1300, Bethesda, MD 20814"
- ]
+ ],
+ "review_verified": false
}
- ]
+ ],
+ "reconciled_at": "2026-08-07 09:50:33"
}
\ No newline at end of file
diff --git a/data/manifest.json b/data/manifest.json
index 5466570..9cce4a8 100644
--- a/data/manifest.json
+++ b/data/manifest.json
@@ -19,7 +19,8 @@
"url": "https://vimeo.com/1199114985",
"duration": 4051,
"caption_chars": 58625,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "June 04, 2026"
},
{
"id": 1178561985,
@@ -59,7 +60,8 @@
"url": "https://vimeo.com/1106281388",
"duration": 4122,
"caption_chars": 74419,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "July 31, 2025"
},
{
"id": 1083190047,
@@ -107,7 +109,8 @@
"url": "https://vimeo.com/1079649123",
"duration": 3750,
"caption_chars": 57666,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "April 25, 2025"
},
{
"id": 1059913595,
@@ -123,7 +126,8 @@
"url": "https://vimeo.com/1056513923",
"duration": 3012,
"caption_chars": 48067,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "February 12, 2025"
},
{
"id": 1039101858,
@@ -131,7 +135,8 @@
"url": "https://vimeo.com/1039101858",
"duration": 4613,
"caption_chars": 71555,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "December 13, 2024"
},
{
"id": 1012976399,
@@ -139,7 +144,8 @@
"url": "https://vimeo.com/1012976399",
"duration": 3050,
"caption_chars": 51652,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "September 19, 2024"
},
{
"id": 989909369,
@@ -163,7 +169,8 @@
"url": "https://vimeo.com/953281926",
"duration": 3656,
"caption_chars": 60628,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "June 03, 2024"
},
{
"id": 931863337,
@@ -171,7 +178,8 @@
"url": "https://vimeo.com/931863337",
"duration": 3678,
"caption_chars": 57234,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "March 21, 2024"
},
{
"id": 911412212,
@@ -179,7 +187,8 @@
"url": "https://vimeo.com/911412212",
"duration": 4139,
"caption_chars": 62340,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "February 09, 2024"
},
{
"id": 906276616,
@@ -187,7 +196,8 @@
"url": "https://vimeo.com/906276616",
"duration": 3601,
"caption_chars": 54030,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "January 19, 2024"
},
{
"id": 886025667,
@@ -195,7 +205,8 @@
"url": "https://vimeo.com/886025667",
"duration": 3521,
"caption_chars": 48930,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "November 17, 2023"
},
{
"id": 868849453,
@@ -203,7 +214,8 @@
"url": "https://vimeo.com/868849453",
"duration": 3690,
"caption_chars": 66741,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "September 21, 2023"
},
{
"id": 865035925,
@@ -227,7 +239,8 @@
"url": "https://vimeo.com/852462696",
"duration": 3910,
"caption_chars": 56811,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "August 09, 2023"
},
{
"id": 831673533,
@@ -283,7 +296,8 @@
"url": "https://vimeo.com/795355693",
"duration": 2883,
"caption_chars": 45629,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "January 30, 2023"
},
{
"id": 771348410,
@@ -291,7 +305,8 @@
"url": "https://vimeo.com/771348410",
"duration": 3065,
"caption_chars": 45097,
- "has_captions": true
+ "has_captions": true,
+ "air_date": "November 14, 2022"
},
{
"id": 763447786,
diff --git a/data/rentvreview.json b/data/rentvreview.json
index 92e303a..3532e40 100644
--- a/data/rentvreview.json
+++ b/data/rentvreview.json
@@ -1,78 +1,249 @@
{
- "771348410": {
- "rv_id": "1909",
- "url": "https://www.rentvreview.com/Videos/View/1909",
- "vimeo": "771348410",
- "title": "Commercial Real Estate Talk, Episode #1 - Bill Shopoff 9677 views Video added by Commercia",
- "sponsors": [],
- "date": "November 14, 2022",
- "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, which is celebrating its 30th Anniversar"
+ "1200839794": {
+ "rv_id": "3255",
+ "url": "https://www.rentvreview.com/Videos/View/3255",
+ "title": "CRE Talk Episode #22 with Bill Shopoff In this episode of Commercial Real Estate Talk with",
+ "ep": 22,
+ "sponsors": [
+ "Rockefeller Group",
+ "Chase Partners",
+ "Provident Savings Bank",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "",
+ "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, a very active developer of major long-te"
},
- "795355693": {
- "rv_id": "1910",
- "url": "https://www.rentvreview.com/Videos/View/1910",
- "vimeo": "795355693",
- "title": "Commercial Real Estate Talk, Episode #2 - Sandy Sigal 7118 views Video added by Commercial",
+ "1199114985": {
+ "rv_id": "3254",
+ "url": "https://www.rentvreview.com/Videos/View/3254",
+ "title": "CRE Talk Episode #21 - Daniel Weiss In this episode of Commercial Real Estate Talk with St",
+ "ep": 21,
+ "sponsors": [
+ "Rockefeller Group",
+ "Chase Partners",
+ "Provident Savings Bank",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "June 04, 2026",
+ "guest_note": "Daniel Weiss \u2014 President of Strauss Investments, an extremely active investor in commercial properties a"
+ },
+ "1178561985": {
+ "rv_id": "3158",
+ "url": "https://www.rentvreview.com/Videos/View/3158",
+ "title": "CRE Talk Episode #20 - Colton Sudberry In this episode of Commercial Real Estate Talk with",
+ "ep": 20,
+ "sponsors": [
+ "Rockefeller Group",
+ "Chase Partners",
+ "Provident Savings Bank",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "",
+ "guest_note": "Colton Sudberry \u2014 President & CEO of Sudberry Properties, an extremely active developer of large, master-pl"
+ },
+ "1138312637": {
+ "rv_id": "3065",
+ "url": "https://www.rentvreview.com/Videos/View/3065",
+ "title": "CRE Talk Episode #19 - Chris Tourtellotte In this episode of Commercial Real Estate Talk w",
+ "ep": 19,
"sponsors": [],
- "date": "January 30, 2023",
- "guest_note": "Sandy SIgal \u2014 President and CEO of NewMark Merrill Companies"
+ "date": "",
+ "guest_note": "Chris Tourtellotte \u2014 Managing Director with LaTerra Development, one of the most prolific multifamily develop"
},
- "953281926": {
- "rv_id": "2493",
- "url": "https://www.rentvreview.com/Videos/View/2493",
- "vimeo": "953281926",
- "title": "RENTV CRE Talk Episode #11 - Michael Rademaker 9942 views Video added by Commercial Real E",
+ "1115700624": {
+ "rv_id": "2909",
+ "url": "https://www.rentvreview.com/Videos/View/2909",
+ "title": "RENTV CRE Talk Episode #18 - Terry Tallen In this episode of Commercial Real Estate Talk w",
+ "ep": 18,
"sponsors": [
- "Paramount Property Tax Appeal",
+ "Chase Partners",
"Commercial Real Estate Inspectors",
"Fidelity Mortgage Lenders"
],
- "date": "June 03, 2024",
- "guest_note": "Michael Rademaker \u2014 Founder and CEO of MGR Real Estate, his Ontario-based company the has a residential and"
+ "date": "",
+ "guest_note": ""
},
- "1039101858": {
- "rv_id": "2642",
- "url": "https://www.rentvreview.com/Videos/View/2642",
- "vimeo": "1039101858",
- "title": "RENTV CRE Talk Episode #13 - Ethan Penner 4876 views Video added by Commercial Real Estate",
+ "1106281388": {
+ "rv_id": "2810",
+ "url": "https://www.rentvreview.com/Videos/View/2810",
+ "title": "RENTV CRE Talk Episode #17 - Christopher Rising In this episode of Commercial Real Estate ",
+ "ep": 17,
"sponsors": [
"Chase Partners",
"Commercial Real Estate Inspectors",
"Fidelity Mortgage Lenders"
],
- "date": "December 13, 2024",
- "guest_note": "Ethan Penner \u2014 Founder & CEO of Mosaic Real Estate Investors, an iconic figure in the real estate fina"
+ "date": "July 31, 2025",
+ "guest_note": ""
+ },
+ "1079649123": {
+ "rv_id": "2746",
+ "url": "https://www.rentvreview.com/Videos/View/2746",
+ "title": "RENTV CRE Talk Episode #16 - Alex Zikakis In this episode of Commercial Real Estate Talk w",
+ "ep": 16,
+ "sponsors": [
+ "Chase Partners",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "April 25, 2025",
+ "guest_note": "Alex Zikakis \u2014 President of Capstone Advisors, the San Diego-based owner and operator of retail properti"
+ },
+ "1059913595": {
+ "rv_id": "2727",
+ "url": "https://www.rentvreview.com/Videos/View/2727",
+ "title": "RENTV CRE Talk Episode #15 - Marc Brutten In this episode of Commercial Real Estate Talk w",
+ "ep": 15,
+ "sponsors": [],
+ "date": "",
+ "guest_note": "Marc Brutten \u2014 CEO of Brutten Global, headquartered in San Diego"
},
"1056513923": {
"rv_id": "2726",
"url": "https://www.rentvreview.com/Videos/View/2726",
- "vimeo": "1056513923",
- "title": "RENTV CRE Talk Episode #14 - John McNellis 3573 views Video added by Commercial Real Estat",
+ "title": "RENTV CRE Talk Episode #14 - John McNellis In this episode of Commercial Real Estate Talk,",
+ "ep": 14,
"sponsors": [],
"date": "February 12, 2025",
"guest_note": "John McNellis \u2014 Partner at McNellis Partners, an owner, investor and developer of shopping centers, mai"
},
- "1200839794": {
- "rv_id": "3255",
- "url": "https://www.rentvreview.com/Videos/View/3255",
- "vimeo": "1200839794",
- "title": "CRE Talk Episode #22 with Bill Shopoff 2034 views Video added by Commercial Real Estate Ta",
+ "1039101858": {
+ "rv_id": "2642",
+ "url": "https://www.rentvreview.com/Videos/View/2642",
+ "title": "RENTV CRE Talk Episode #13 - Ethan Penner In this episode of Commercial Real Estate Talk w",
+ "ep": 13,
"sponsors": [
- "Rockefeller Group",
"Chase Partners",
- "Provident Savings Bank",
+ "Commercial Real Estate Inspectors",
"Fidelity Mortgage Lenders"
],
- "date": "June 10, 2026",
- "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, a very active developer of major long-te"
+ "date": "December 13, 2024",
+ "guest_note": "Ethan Penner \u2014 Founder & CEO of Mosaic Real Estate Investors, an iconic figure in the real estate fina"
+ },
+ "1012976399": {
+ "rv_id": "2601",
+ "url": "https://www.rentvreview.com/Videos/View/2601",
+ "title": "RENTV CRE Talk Episode #12 - Kaitlin Arduino In this episode of Commercial Real Estate Tal",
+ "ep": 12,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "September 19, 2024",
+ "guest_note": "Kaitlin Arduino \u2014 President of Murphy Development, the family-owned company now in its fourth decade that i"
+ },
+ "953281926": {
+ "rv_id": "2493",
+ "url": "https://www.rentvreview.com/Videos/View/2493",
+ "title": "RENTV CRE Talk Episode #11 - Michael Rademaker In this episode of Commercial Real Estate T",
+ "ep": 11,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "June 03, 2024",
+ "guest_note": "Michael Rademaker \u2014 Founder and CEO of MGR Real Estate, his Ontario-based company the has a residential and"
+ },
+ "931863337": {
+ "rv_id": "2447",
+ "url": "https://www.rentvreview.com/Videos/View/2447",
+ "title": "RENTV CRE Talk Episode #10 Henry Manoucheri In this episode of Commercial Real Estate Talk",
+ "ep": 10,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "March 21, 2024",
+ "guest_note": "Henry Manoucheri \u2014 Chairman and CEO of Universe Holdings, the multifamily real estate investment firm that"
+ },
+ "911412212": {
+ "rv_id": "2392",
+ "url": "https://www.rentvreview.com/Videos/View/2392",
+ "title": "RENTV CRE Talk Episode #9 Eddie Ring In this episode of Commercial Real Estate Talk with S",
+ "ep": 9,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "February 09, 2024",
+ "guest_note": "Eddie Ring \u2014 Founder and CEO of New Standard Equities, the multifamily real estate investment firm t"
+ },
+ "906276616": {
+ "rv_id": "2346",
+ "url": "https://www.rentvreview.com/Videos/View/2346",
+ "title": "RENTV CRE Talk Episode #8 Erwin Bucy In this episode of Commercial Real Estate Talk with S",
+ "ep": 8,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "January 19, 2024",
+ "guest_note": ""
+ },
+ "886025667": {
+ "rv_id": "2122",
+ "url": "https://www.rentvreview.com/Videos/View/2122",
+ "title": "RENTV CRE Talk Episode #7 Chuck Hershson In this episode of Commercial Real Estate Talk wi",
+ "ep": 7,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Fidelity Mortgage Lenders"
+ ],
+ "date": "November 17, 2023",
+ "guest_note": ""
+ },
+ "868849453": {
+ "rv_id": "2107",
+ "url": "https://www.rentvreview.com/Videos/View/2107",
+ "title": "RENTV CRE Talk Episode #6 Barry Saywitz In this episode of Commercial Real Estate Talk wit",
+ "ep": 6,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Redwood Mortgage"
+ ],
+ "date": "September 21, 2023",
+ "guest_note": "Barry Saywitz \u2014 President & Founder of The Saywitz Company, the commercial real estate brokerage firm, an"
},
"852462696": {
"rv_id": "2033",
"url": "https://www.rentvreview.com/Videos/View/2033",
- "vimeo": "852462696",
- "title": "RENTV CRE Talk Episode #5 Barry DiRaimondo 14679 views Video added by Commercial Real Esta",
- "sponsors": [],
+ "title": "RENTV CRE Talk Episode #5 Barry DiRaimondo In this episode of Commercial Real Estate Talk ",
+ "ep": 5,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Redwood Mortgage"
+ ],
"date": "August 09, 2023",
"guest_note": ""
+ },
+ "795355693": {
+ "rv_id": "1910",
+ "url": "https://www.rentvreview.com/Videos/View/1910",
+ "title": "Commercial Real Estate Talk, Episode #2 - Sandy Sigal In this episode of Commercial Real E",
+ "ep": 2,
+ "sponsors": [],
+ "date": "January 30, 2023",
+ "guest_note": "Sandy SIgal \u2014 President and CEO of NewMark Merrill Companies"
+ },
+ "771348410": {
+ "rv_id": "1909",
+ "url": "https://www.rentvreview.com/Videos/View/1909",
+ "title": "Commercial Real Estate Talk, Episode #1 - Bill Shopoff In this first episode of Commercial",
+ "ep": 1,
+ "sponsors": [
+ "Paramount Property Tax Appeal",
+ "Commercial Real Estate Inspectors",
+ "Redwood Mortgage"
+ ],
+ "date": "November 14, 2022",
+ "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, which is celebrating its 30th Anniversar"
}
}
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 4d1e23d..f0bc12f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -183,7 +183,8 @@ function renderCards(main,L){
const c=el("div","card");
c.innerHTML=`<h3 onclick='openAdv(${JSON.stringify(a.name)})'>${esc(a.name)}</h3>
<div class="row"><span class="badge cat">${esc(a.category||"other")}</span>
- <span class="appear" onclick='openAdv(${JSON.stringify(a.name)})'>${a.appearances} run${a.appearances>1?"s":""}</span></div>
+ <span class="appear" onclick='openAdv(${JSON.stringify(a.name)})'>${a.appearances} run${a.appearances>1?"s":""}</span>
+ ${a.review_verified?`<span class="badge" style="color:var(--gold);border-color:#3a3320" title="Confirmed by RENTV's official sponsor list on The REview (${a.review_appearances} episodes)">✓ REview</span>`:""}</div>
<div class="pitch">${esc(a.pitch||"")}</div>
${(a.websites||[]).map(w=>`<div class="kv">🌐 <a href="${siteURL(esc(w))}" target="_blank" rel="noopener">${esc(w)}</a></div>`).join("")}
${(a.phones||[]).map(p=>`<div class="kv">📞 <a href="${telURL(p)}">${esc(p)}</a></div>`).join("")}
@@ -230,7 +231,7 @@ function renderCards(main,L){
const c=el("div","card"); const fr=FRAMES[v.id];
c.innerHTML=`${fr&&fr.poster?`<img src="${esc(fr.poster)}" loading="lazy" onclick="openEpisode(${v.id})" style="width:100%;border-radius:8px;cursor:pointer;border:1px solid var(--line)">`:""}
<h3 onclick="openEpisode(${v.id})" style="font-size:14px">${esc(v.title)}</h3>
- <div class="kv">⏱ ${(v.duration/60).toFixed(0)} min · 📝 ${(v.caption_chars/1000).toFixed(1)}k chars</div>
+ <div class="kv">${v.air_date?"📅 "+esc(v.air_date)+" · ":""}⏱ ${(v.duration/60).toFixed(0)} min · 📝 ${(v.caption_chars/1000).toFixed(1)}k chars</div>
${fr&&fr.logos&&fr.logos.length?`<div class="row"><span class="kv">on-screen:</span>${fr.logos.map(l=>`<span class="chip">${esc(l)}</span>`).join("")}</div>`:""}
<div class="row"><span class="badge">${v.has_captions?"transcribed":"no captions"}</span>
<span class="chip ep" onclick="openEpisode(${v.id})">▶ open dossier</span></div>`;
diff --git a/scripts/harvest-rentvreview.py b/scripts/harvest-rentvreview.py
index b17990c..5a1982e 100644
--- a/scripts/harvest-rentvreview.py
+++ b/scripts/harvest-rentvreview.py
@@ -1,95 +1,84 @@
#!/usr/bin/env python3
-"""Harvest AUTHORITATIVE episode data from rentvreview.com ("The REview").
+"""Harvest AUTHORITATIVE episode data from rentvreview.com "The REview".
-Each /Videos/View/<id> page is server-rendered and carries, in plain HTML:
- - data-video-external-id="<vimeoId>" (maps REview episode -> our Vimeo video)
- - "... Sponsored by: A; B; and C. To be a part ..." (authoritative sponsor list)
- - the guest/synopsis prose + "Date Created: <date>"
-This is cleaner than transcript inference and covers episodes predating the Vimeo feed.
+The CRE Talk producer page /Producers/View/618 lists EVERY episode inline with its
+title, "Sponsored by:" list, air date, and guest prose — one server-rendered fetch,
+free, no API/DRM. We parse it into per-episode records and join to our Vimeo library
+by episode number (both title sets carry "Episode #N").
-We BFS from known CRE Talk pages, following the 6 related-video links per page, keeping
-pages whose Vimeo id matches our library OR whose title is a CRE Talk episode. Free,
-bounded (MAX_FETCH), no API/DRM.
-
-Output: data/rentvreview.json { "<vimeoId>": {rv_id,url,sponsors[],guest_note,date,title} }
-Env: MAX_FETCH (default 120), SEEDS (comma ids)
+Output: data/rentvreview.json { "<vimeoId>": {rv_id,url,title,ep,sponsors[],date,guest_note} }
+Env: PRODUCER (default 618)
"""
-import json, os, re, time, urllib.request, html as _html
-from collections import deque
+import json, os, re, urllib.request, html as _html
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
MANIFEST = os.path.join(ROOT, "data", "manifest.json")
OUT = os.path.join(ROOT, "data", "rentvreview.json")
UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1"
-MAX_FETCH = int(os.environ.get("MAX_FETCH", "120"))
-SEEDS = [s for s in os.environ.get("SEEDS", "1909,1910,2493,2642,2726,3255,1034,1650,2033,2298,2898,3273").split(",") if s]
+PRODUCER = os.environ.get("PRODUCER", "618")
-VIMEO_IDS = {str(v["id"]) for v in json.load(open(MANIFEST))["videos"]}
+STOP = re.compile(r"(To be a part|If you have|Thank you|please email|\bhere\b)", re.I)
-def fetch(rv_id):
- try:
- return urllib.request.urlopen(urllib.request.Request(
- f"https://www.rentvreview.com/Videos/View/{rv_id}", headers={"User-Agent": UA}), timeout=20
- ).read().decode("utf-8", "ignore")
- except Exception:
- return ""
+def epnum(title):
+ m = re.search(r"Episode\s*#?\s*(\d+)", title or "", re.I)
+ return int(m.group(1)) if m else None
-def parse(h):
- ext = re.search(r'data-video-external-id="(\d+)"', h)
- vimeo = ext.group(1) if ext else ""
- text = _html.unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", h)))
- title = ""
- mt = re.search(r"(RENTV CRE Talk Episode #?\d+[^|<]*|CRE Talk,? Episode #?\d+[^|<]*|Commercial Real Estate Talk,? Episode #?\d+[^|<]*)", text)
- if mt:
- title = mt.group(1).strip()[:90]
- sponsors = []
- ms = re.search(r"Sponsored by[:\s]+(.+?)\.\s*(?:To be a part|If you|Thank you|$)", text, re.I)
- if ms:
- raw = ms.group(1)
- parts = re.split(r";|,|\band\b", raw)
- sponsors = [re.sub(r"\s+", " ", p).strip().title() for p in parts if p.strip() and len(p.strip()) > 2]
- date = ""
- md = re.search(r"Date Created:\s*([A-Za-z]+ \d{1,2}, \d{4})", text)
- if md:
- date = md.group(1)
- guest = ""
- mg = re.search(r"interview\s+([A-Z][a-zA-Z.\-]+ [A-Z][a-zA-Z.\-]+)[,]?\s+((?:President|CEO|Founder|Partner|Managing|Chief|Head|Owner|Chairman)[^.]{0,80})", text)
- if mg:
- guest = f"{mg.group(1)} — {mg.group(2).strip()}"[:120]
- related = re.findall(r'href="/Videos/View/(\d+)"', h)
- return {"vimeo": vimeo, "title": title, "sponsors": sponsors, "date": date, "guest_note": guest}, related
+def clean_sponsors(raw):
+ raw = re.split(r"To be a part|If you have|Thank you", raw, 1)[0]
+ parts = re.split(r";|\band\b|,", raw)
+ out = []
+ for p in parts:
+ s = re.sub(r"\s+", " ", p).strip(" .;:").title()
+ if len(s) > 2 and not s.lower().startswith(("http", "www")):
+ out.append(s)
+ return out
def main():
+ lib = json.load(open(MANIFEST))["videos"]
+ by_ep = {}
+ for v in lib:
+ n = epnum(v["title"])
+ if n is not None:
+ by_ep[n] = str(v["id"])
+
+ html = urllib.request.urlopen(urllib.request.Request(
+ f"https://www.rentvreview.com/Producers/View/{PRODUCER}", headers={"User-Agent": UA}), timeout=30
+ ).read().decode("utf-8", "ignore")
+
+ # split into per-video segments by the view links (order = listing order)
+ segs = re.split(r'href="/Videos/View/(\d+)"', html)
+ # segs = [pre, id1, block1, id2, block2, ...]
out = json.load(open(OUT)) if os.path.exists(OUT) else {}
- seen, q, fetched = set(), deque(SEEDS), 0
- print(f"[rentvreview] BFS from {len(SEEDS)} seeds, cap {MAX_FETCH}, matching {len(VIMEO_IDS)} vimeo ids")
- while q and fetched < MAX_FETCH:
- rv = q.popleft()
- if rv in seen:
+ mapped = 0
+ # each rv id appears twice (thumbnail link + title/description link); the title
+ # block is the one that parses — so process every segment and keep those with a title.
+ for i in range(1, len(segs) - 1, 2):
+ rv_id = segs[i]
+ block = _html.unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", segs[i + 1])))[:1600]
+ mt = re.search(r"((?:RENTV )?CRE Talk,? Episode #?\d+[^|<.]*|Commercial Real Estate Talk,? Episode #?\d+[^|<.]*)", block)
+ title = mt.group(1).strip() if mt else ""
+ n = epnum(title)
+ if n is None or n not in by_ep:
continue
- seen.add(rv)
- h = fetch(rv)
- fetched += 1
- if not h:
- continue
- rec, related = parse(h)
- is_cre = ("Commercial Real Estate Talk" in h or "CRE Talk" in h)
- if rec["vimeo"] and (rec["vimeo"] in VIMEO_IDS or is_cre):
- key = rec["vimeo"]
- out[key] = {"rv_id": rv, "url": f"https://www.rentvreview.com/Videos/View/{rv}", **rec}
- # follow related to find sibling episodes
- for r in related:
- if r not in seen:
- q.append(r)
- if fetched % 15 == 0:
- print(f" fetched={fetched} matched={len(out)} queue={len(q)}")
- time.sleep(0.3)
+ vimeo = by_ep[n]
+ ms = re.search(r"Sponsored by[:\s]+(.+?)\.\s", block, re.I)
+ sponsors = clean_sponsors(ms.group(1)) if ms else []
+ md = re.search(r"Date Created:\s*([A-Za-z]+ \d{1,2}, \d{4})", block)
+ date = md.group(1) if md else ""
+ mg = re.search(r"interview\s+([A-Z][a-zA-Z.\-]+ [A-Z][a-zA-Z.\-]+)[,]?\s+((?:President|CEO|Co-?founder|Founder|Partner|Managing|Chief|Head|Owner|Chairman)[^.]{0,80})", block)
+ guest = f"{mg.group(1)} — {mg.group(2).strip()}"[:130] if mg else ""
+ out[vimeo] = {"rv_id": rv_id, "url": f"https://www.rentvreview.com/Videos/View/{rv_id}",
+ "title": title[:90], "ep": n, "sponsors": sponsors, "date": date, "guest_note": guest}
+ mapped += 1
+
json.dump(out, open(OUT, "w"), indent=1)
- matched_lib = sum(1 for k in out if k in VIMEO_IDS)
- print(f"[rentvreview] DONE fetched={fetched} matched={len(out)} (of which {matched_lib} in our Vimeo library) -> {OUT}")
+ withsp = sum(1 for r in out.values() if r.get("sponsors"))
+ print(f"[rentvreview] producer {PRODUCER}: mapped {mapped} episodes this run | total {len(out)} | with sponsors {withsp}")
+ for k, r in sorted(out.items(), key=lambda x: -(x[1].get("ep") or 0)):
+ print(f" ep{r.get('ep'):>2} {r.get('date',''):>18} sponsors={r.get('sponsors')}")
if __name__ == "__main__":
diff --git a/scripts/reconcile-review.py b/scripts/reconcile-review.py
new file mode 100644
index 0000000..1386c5c
--- /dev/null
+++ b/scripts/reconcile-review.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+"""Reconcile the AUTHORITATIVE rentvreview.com data into the engine.
+
+- Marks each advertiser review_verified when RENTV's official "Sponsored by" lists it,
+ with an authoritative review_appearances count + the episodes.
+- Stamps each video's real air date (from The REview) onto the manifest.
+- Reports agreement between our transcript extraction and RENTV's official record.
+"""
+import json, os, re
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ADV = os.path.join(ROOT, "data", "advertisers.json")
+MANI = os.path.join(ROOT, "data", "manifest.json")
+RV = os.path.join(ROOT, "data", "rentvreview.json")
+
+
+def nk(s):
+ return re.sub(r"[^a-z0-9]", "", (s or "").lower())
+
+
+def main():
+ rv = json.load(open(RV))
+ advdoc = json.load(open(ADV)); advs = advdoc["advertisers"]
+ mani = json.load(open(MANI))
+
+ # authoritative advertiser -> set(vimeo episode ids) from RENTV official sponsor lists
+ auth = {}
+ for vid, r in rv.items():
+ for s in r.get("sponsors", []):
+ auth.setdefault(nk(s), {"name": s, "eps": set()})["eps"].add(vid)
+
+ # stamp real air dates onto manifest
+ dated = 0
+ for v in mani["videos"]:
+ r = rv.get(str(v["id"]))
+ if r and r.get("date"):
+ v["air_date"] = r["date"]; dated += 1
+ json.dump(mani, open(MANI, "w"), indent=1)
+
+ # cross-verify advertisers
+ verified = 0
+ for a in advs:
+ keys = [nk(a["name"])] + [nk(x) for x in a.get("aliases", [])]
+ hit = None
+ for k in keys:
+ for ak, av in auth.items():
+ if k and (k == ak or (len(k) > 5 and (k in ak or ak in k))):
+ hit = av; break
+ if hit:
+ break
+ if hit:
+ a["review_verified"] = True
+ a["review_appearances"] = len(hit["eps"])
+ a["review_official_name"] = hit["name"]
+ verified += 1
+ else:
+ a["review_verified"] = False
+ advdoc["reconciled_at"] = __import__("time").strftime("%Y-%m-%d %H:%M:%S")
+ json.dump(advdoc, open(ADV, "w"), indent=1)
+
+ # agreement report
+ print(f"[reconcile] episodes dated from REview: {dated}")
+ print(f"[reconcile] advertisers REview-verified: {verified}/{len(advs)}")
+ print("[reconcile] authoritative sponsors (official appearances):")
+ for ak, av in sorted(auth.items(), key=lambda x: -len(x[1]["eps"])):
+ # compare to our transcript count
+ ours = next((a for a in advs if nk(a["name"]) == ak or av["name"].lower() in a["name"].lower()), None)
+ oc = ours["appearances"] if ours else "—"
+ print(f" {av['name']:<34} official={len(av['eps']):>2} ours(transcript)={oc}")
+
+
+if __name__ == "__main__":
+ main()
← 750f51f Integrate RENTV podcast (SoundCloud rentvnews) + The REview
·
back to Rentv Ad Engine
·
make ad-engine mountable under a path prefix (BASE_PATH -> < 87ad1ae →